PostGIS  2.5.0dev-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 #include <postgres.h>
31 #include <fmgr.h>
32 #include <funcapi.h>
33 #include <utils/builtins.h> /* for text_to_cstring() */
34 #include "utils/lsyscache.h" /* for get_typlenbyvalalign */
35 #include "utils/array.h" /* for ArrayType */
36 #include "catalog/pg_type.h" /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */
37 
38 #include "../../postgis_config.h"
39 
40 
41 #include "access/htup_details.h" /* for heap_form_tuple() */
42 
43 
44 #include "rtpostgis.h"
45 
46 /* Get all the properties of a raster band */
47 Datum RASTER_getBandPixelType(PG_FUNCTION_ARGS);
48 Datum RASTER_getBandPixelTypeName(PG_FUNCTION_ARGS);
49 Datum RASTER_getBandNoDataValue(PG_FUNCTION_ARGS);
50 Datum RASTER_getBandPath(PG_FUNCTION_ARGS);
51 Datum RASTER_bandIsNoData(PG_FUNCTION_ARGS);
52 
53 /* get raster band's meta data */
54 Datum RASTER_bandmetadata(PG_FUNCTION_ARGS);
55 
56 /* Set all the properties of a raster band */
57 Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS);
58 Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS);
59 Datum RASTER_setBandPath(PG_FUNCTION_ARGS);
60 Datum RASTER_setBandIndex(PG_FUNCTION_ARGS);
61 
67 Datum RASTER_getBandPixelType(PG_FUNCTION_ARGS)
68 {
69  rt_pgraster *pgraster = NULL;
70  rt_raster raster = NULL;
71  rt_band band = NULL;
72  rt_pixtype pixtype;
73  int32_t bandindex;
74 
75  /* Deserialize raster */
76  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
77  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
78 
79  /* Index is 1-based */
80  bandindex = PG_GETARG_INT32(1);
81  if ( bandindex < 1 ) {
82  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
83  PG_FREE_IF_COPY(pgraster, 0);
84  PG_RETURN_NULL();
85  }
86 
87  raster = rt_raster_deserialize(pgraster, FALSE);
88  if ( ! raster ) {
89  PG_FREE_IF_COPY(pgraster, 0);
90  elog(ERROR, "RASTER_getBandPixelType: Could not deserialize raster");
91  PG_RETURN_NULL();
92  }
93 
94  /* Fetch requested band and its pixel type */
95  band = rt_raster_get_band(raster, bandindex - 1);
96  if ( ! band ) {
97  elog(NOTICE, "Could not find raster band of index %d when getting pixel type. Returning NULL", bandindex);
98  rt_raster_destroy(raster);
99  PG_FREE_IF_COPY(pgraster, 0);
100  PG_RETURN_NULL();
101  }
102 
103  pixtype = rt_band_get_pixtype(band);
104 
105  rt_raster_destroy(raster);
106  PG_FREE_IF_COPY(pgraster, 0);
107 
108  PG_RETURN_INT32(pixtype);
109 }
110 
117 Datum RASTER_getBandPixelTypeName(PG_FUNCTION_ARGS)
118 {
119  rt_pgraster *pgraster = NULL;
120  rt_raster raster = NULL;
121  rt_band band = NULL;
122  rt_pixtype pixtype;
123  int32_t bandindex;
124  const size_t name_size = 8; /* size of type name */
125  size_t size = 0;
126  char *ptr = NULL;
127  text *result = NULL;
128 
129  /* Deserialize raster */
130  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
131  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
132 
133  /* Index is 1-based */
134  bandindex = PG_GETARG_INT32(1);
135  if ( bandindex < 1 ) {
136  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
137  PG_FREE_IF_COPY(pgraster, 0);
138  PG_RETURN_NULL();
139  }
140 
141  raster = rt_raster_deserialize(pgraster, FALSE);
142  if ( ! raster ) {
143  PG_FREE_IF_COPY(pgraster, 0);
144  elog(ERROR, "RASTER_getBandPixelTypeName: Could not deserialize raster");
145  PG_RETURN_NULL();
146  }
147 
148  /* Fetch requested band and its pixel type */
149  band = rt_raster_get_band(raster, bandindex - 1);
150  if ( ! band ) {
151  elog(NOTICE, "Could not find raster band of index %d when getting pixel type name. Returning NULL", bandindex);
152  rt_raster_destroy(raster);
153  PG_FREE_IF_COPY(pgraster, 0);
154  PG_RETURN_NULL();
155  }
156 
157  pixtype = rt_band_get_pixtype(band);
158 
159  result = palloc(VARHDRSZ + name_size);
160  /* We don't need to check for NULL pointer, because if out of memory, palloc
161  * exit via elog(ERROR). It never returns NULL.
162  */
163 
164  memset(VARDATA(result), 0, name_size);
165  ptr = (char *)result + VARHDRSZ;
166  strcpy(ptr, rt_pixtype_name(pixtype));
167 
168  size = VARHDRSZ + strlen(ptr);
169  SET_VARSIZE(result, size);
170 
171  rt_raster_destroy(raster);
172  PG_FREE_IF_COPY(pgraster, 0);
173 
174  PG_RETURN_TEXT_P(result);
175 }
176 
182 Datum RASTER_getBandNoDataValue(PG_FUNCTION_ARGS)
183 {
184  rt_pgraster *pgraster = NULL;
185  rt_raster raster = NULL;
186  rt_band band = NULL;
187  int32_t bandindex;
188  double nodata;
189 
190  /* Deserialize raster */
191  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
192  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
193 
194  /* Index is 1-based */
195  bandindex = PG_GETARG_INT32(1);
196  if ( bandindex < 1 ) {
197  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
198  PG_FREE_IF_COPY(pgraster, 0);
199  PG_RETURN_NULL();
200  }
201 
202  raster = rt_raster_deserialize(pgraster, FALSE);
203  if ( ! raster ) {
204  PG_FREE_IF_COPY(pgraster, 0);
205  elog(ERROR, "RASTER_getBandNoDataValue: Could not deserialize raster");
206  PG_RETURN_NULL();
207  }
208 
209  /* Fetch requested band and its nodata value */
210  band = rt_raster_get_band(raster, bandindex - 1);
211  if ( ! band ) {
212  elog(NOTICE, "Could not find raster band of index %d when getting band nodata value. Returning NULL", bandindex);
213  rt_raster_destroy(raster);
214  PG_FREE_IF_COPY(pgraster, 0);
215  PG_RETURN_NULL();
216  }
217 
218  if ( ! rt_band_get_hasnodata_flag(band) ) {
219  /* Raster does not have a nodata value set so we return NULL */
220  rt_raster_destroy(raster);
221  PG_FREE_IF_COPY(pgraster, 0);
222  PG_RETURN_NULL();
223  }
224 
225  rt_band_get_nodata(band, &nodata);
226 
227  rt_raster_destroy(raster);
228  PG_FREE_IF_COPY(pgraster, 0);
229 
230  PG_RETURN_FLOAT8(nodata);
231 }
232 
233 
235 Datum RASTER_bandIsNoData(PG_FUNCTION_ARGS)
236 {
237  rt_pgraster *pgraster = NULL;
238  rt_raster raster = NULL;
239  rt_band band = NULL;
240  int32_t bandindex;
241  bool forcechecking = FALSE;
242  bool bandisnodata = FALSE;
243 
244  /* Index is 1-based */
245  bandindex = PG_GETARG_INT32(1);
246  if ( bandindex < 1 ) {
247  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
248  PG_RETURN_NULL();
249  }
250 
251  /* Deserialize raster */
252  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
253  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
254 
255  raster = rt_raster_deserialize(pgraster, FALSE);
256  if ( ! raster ) {
257  PG_FREE_IF_COPY(pgraster, 0);
258  elog(ERROR, "RASTER_bandIsNoData: Could not deserialize raster");
259  PG_RETURN_NULL();
260  }
261 
262  /* Fetch requested band and its nodata value */
263  band = rt_raster_get_band(raster, bandindex - 1);
264  if ( ! band ) {
265  elog(NOTICE, "Could not find raster band of index %d when determining if band is nodata. Returning NULL", bandindex);
266  rt_raster_destroy(raster);
267  PG_FREE_IF_COPY(pgraster, 0);
268  PG_RETURN_NULL();
269  }
270 
271  forcechecking = PG_GETARG_BOOL(2);
272 
273  bandisnodata = (forcechecking) ?
275 
276  rt_raster_destroy(raster);
277  PG_FREE_IF_COPY(pgraster, 0);
278 
279  PG_RETURN_BOOL(bandisnodata);
280 }
281 
286 Datum RASTER_getBandPath(PG_FUNCTION_ARGS)
287 {
288  rt_pgraster *pgraster = NULL;
289  rt_raster raster = NULL;
290  rt_band band = NULL;
291  int32_t bandindex;
292  const char *bandpath;
293  text *result;
294 
295  /* Index is 1-based */
296  bandindex = PG_GETARG_INT32(1);
297  if ( bandindex < 1 ) {
298  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
299  PG_RETURN_NULL();
300  }
301 
302  /* Deserialize raster */
303  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
304  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
305 
306  raster = rt_raster_deserialize(pgraster, FALSE);
307  if (!raster) {
308  PG_FREE_IF_COPY(pgraster, 0);
309  elog(ERROR, "RASTER_getBandPath: Could not deserialize raster");
310  PG_RETURN_NULL();
311  }
312 
313  /* Fetch requested band */
314  band = rt_raster_get_band(raster, bandindex - 1);
315  if (!band) {
316  elog(
317  NOTICE,
318  "Could not find raster band of index %d when getting band path. Returning NULL",
319  bandindex
320  );
321  rt_raster_destroy(raster);
322  PG_FREE_IF_COPY(pgraster, 0);
323  PG_RETURN_NULL();
324  }
325 
326  bandpath = rt_band_get_ext_path(band);
327  if (!bandpath) {
328  rt_band_destroy(band);
329  rt_raster_destroy(raster);
330  PG_FREE_IF_COPY(pgraster, 0);
331  PG_RETURN_NULL();
332  }
333 
334  result = cstring_to_text(bandpath);
335 
336  rt_band_destroy(band);
337  rt_raster_destroy(raster);
338  PG_FREE_IF_COPY(pgraster, 0);
339 
340  PG_RETURN_TEXT_P(result);
341 }
342 
347 Datum RASTER_bandmetadata(PG_FUNCTION_ARGS)
348 {
349  FuncCallContext *funcctx;
350  TupleDesc tupdesc;
351  int call_cntr;
352  int max_calls;
353 
354  struct bandmetadata {
355  uint32_t bandnum;
356  char *pixeltype;
357  bool hasnodata;
358  double nodataval;
359  bool isoutdb;
360  char *bandpath;
361  uint8_t extbandnum;
362  };
363  struct bandmetadata *bmd = NULL;
364  struct bandmetadata *bmd2 = NULL;
365 
366  HeapTuple tuple;
367  Datum result;
368 
369  if (SRF_IS_FIRSTCALL()) {
370  MemoryContext oldcontext;
371 
372  rt_pgraster *pgraster = NULL;
373  rt_raster raster = NULL;
374  rt_band band = NULL;
375 
376  ArrayType *array;
377  Oid etype;
378  Datum *e;
379  bool *nulls;
380  int16 typlen;
381  bool typbyval;
382  char typalign;
383  int i = 0;
384  int j = 0;
385  int n = 0;
386 
387  uint32_t numBands;
388  uint32_t idx = 1;
389  uint32_t *bandNums = NULL;
390  const char *chartmp = NULL;
391  size_t charlen;
392  uint8_t extbandnum;
393 
394  POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
395 
396  /* create a function context for cross-call persistence */
397  funcctx = SRF_FIRSTCALL_INIT();
398 
399  /* switch to memory context appropriate for multiple function calls */
400  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
401 
402  /* pgraster is null, return null */
403  if (PG_ARGISNULL(0)) {
404  MemoryContextSwitchTo(oldcontext);
405  SRF_RETURN_DONE(funcctx);
406  }
407  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
408 
409  /* raster */
410  raster = rt_raster_deserialize(pgraster, FALSE);
411  if (!raster) {
412  PG_FREE_IF_COPY(pgraster, 0);
413  MemoryContextSwitchTo(oldcontext);
414  elog(ERROR, "RASTER_bandmetadata: Could not deserialize raster");
415  SRF_RETURN_DONE(funcctx);
416  }
417 
418  /* numbands */
419  numBands = rt_raster_get_num_bands(raster);
420  if (numBands < 1) {
421  elog(NOTICE, "Raster provided has no bands");
422  rt_raster_destroy(raster);
423  PG_FREE_IF_COPY(pgraster, 0);
424  MemoryContextSwitchTo(oldcontext);
425  SRF_RETURN_DONE(funcctx);
426  }
427 
428  /* band index */
429  array = PG_GETARG_ARRAYTYPE_P(1);
430  etype = ARR_ELEMTYPE(array);
431  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
432 
433  switch (etype) {
434  case INT2OID:
435  case INT4OID:
436  break;
437  default:
438  rt_raster_destroy(raster);
439  PG_FREE_IF_COPY(pgraster, 0);
440  MemoryContextSwitchTo(oldcontext);
441  elog(ERROR, "RASTER_bandmetadata: Invalid data type for band number(s)");
442  SRF_RETURN_DONE(funcctx);
443  break;
444  }
445 
446  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
447  &nulls, &n);
448 
449  bandNums = palloc(sizeof(uint32_t) * n);
450  for (i = 0, j = 0; i < n; i++) {
451  if (nulls[i]) continue;
452 
453  switch (etype) {
454  case INT2OID:
455  idx = (uint32_t) DatumGetInt16(e[i]);
456  break;
457  case INT4OID:
458  idx = (uint32_t) DatumGetInt32(e[i]);
459  break;
460  }
461 
462  POSTGIS_RT_DEBUGF(3, "band idx (before): %d", idx);
463  if (idx > numBands || idx < 1) {
464  elog(NOTICE, "Invalid band index: %d. Indices must be 1-based. Returning NULL", idx);
465  pfree(bandNums);
466  rt_raster_destroy(raster);
467  PG_FREE_IF_COPY(pgraster, 0);
468  MemoryContextSwitchTo(oldcontext);
469  SRF_RETURN_DONE(funcctx);
470  }
471 
472  bandNums[j] = idx;
473  POSTGIS_RT_DEBUGF(3, "bandNums[%d] = %d", j, bandNums[j]);
474  j++;
475  }
476 
477  if (j < 1) {
478  j = numBands;
479  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
480  for (i = 0; i < j; i++)
481  bandNums[i] = i + 1;
482  }
483  else if (j < n)
484  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
485 
486  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata) * j);
487 
488  for (i = 0; i < j; i++) {
489  band = rt_raster_get_band(raster, bandNums[i] - 1);
490  if (NULL == band) {
491  elog(NOTICE, "Could not get raster band at index %d", bandNums[i]);
492  rt_raster_destroy(raster);
493  PG_FREE_IF_COPY(pgraster, 0);
494  MemoryContextSwitchTo(oldcontext);
495  SRF_RETURN_DONE(funcctx);
496  }
497 
498  /* bandnum */
499  bmd[i].bandnum = bandNums[i];
500 
501  /* pixeltype */
502  chartmp = rt_pixtype_name(rt_band_get_pixtype(band));
503  charlen = strlen(chartmp) + 1;
504  bmd[i].pixeltype = palloc(sizeof(char) * charlen);
505  strncpy(bmd[i].pixeltype, chartmp, charlen);
506 
507  /* hasnodatavalue */
508  if (rt_band_get_hasnodata_flag(band))
509  bmd[i].hasnodata = TRUE;
510  else
511  bmd[i].hasnodata = FALSE;
512 
513  /* nodatavalue */
514  if (bmd[i].hasnodata)
515  rt_band_get_nodata(band, &(bmd[i].nodataval));
516  else
517  bmd[i].nodataval = 0;
518 
519  /* out-db path */
520  chartmp = rt_band_get_ext_path(band);
521  if (chartmp) {
522  charlen = strlen(chartmp) + 1;
523  bmd[i].bandpath = palloc(sizeof(char) * charlen);
524  strncpy(bmd[i].bandpath, chartmp, charlen);
525  }
526  else
527  bmd[i].bandpath = NULL;
528 
529  /* isoutdb */
530  bmd[i].isoutdb = bmd[i].bandpath ? TRUE : FALSE;
531 
532  /* out-db bandnum */
533  if (rt_band_get_ext_band_num(band, &extbandnum) == ES_NONE)
534  bmd[i].extbandnum = extbandnum + 1;
535  else
536  bmd[i].extbandnum = 0;
537 
538  rt_band_destroy(band);
539  }
540 
541  rt_raster_destroy(raster);
542  PG_FREE_IF_COPY(pgraster, 0);
543 
544  /* Store needed information */
545  funcctx->user_fctx = bmd;
546 
547  /* total number of tuples to be returned */
548  funcctx->max_calls = j;
549 
550  /* Build a tuple descriptor for our result type */
551  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
552  MemoryContextSwitchTo(oldcontext);
553  ereport(ERROR, (
554  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
555  errmsg(
556  "function returning record called in context "
557  "that cannot accept type record"
558  )
559  ));
560  }
561 
562  BlessTupleDesc(tupdesc);
563  funcctx->tuple_desc = tupdesc;
564 
565  MemoryContextSwitchTo(oldcontext);
566  }
567 
568  /* stuff done on every call of the function */
569  funcctx = SRF_PERCALL_SETUP();
570 
571  call_cntr = funcctx->call_cntr;
572  max_calls = funcctx->max_calls;
573  tupdesc = funcctx->tuple_desc;
574  bmd2 = funcctx->user_fctx;
575 
576  /* do when there is more left to send */
577  if (call_cntr < max_calls) {
578  int values_length = 6;
579  Datum values[values_length];
580  bool nulls[values_length];
581 
582  memset(nulls, FALSE, sizeof(bool) * values_length);
583 
584  values[0] = UInt32GetDatum(bmd2[call_cntr].bandnum);
585  values[1] = CStringGetTextDatum(bmd2[call_cntr].pixeltype);
586 
587  if (bmd2[call_cntr].hasnodata)
588  values[2] = Float8GetDatum(bmd2[call_cntr].nodataval);
589  else
590  nulls[2] = TRUE;
591 
592  values[3] = BoolGetDatum(bmd2[call_cntr].isoutdb);
593  if (bmd2[call_cntr].bandpath && strlen(bmd2[call_cntr].bandpath)) {
594  values[4] = CStringGetTextDatum(bmd2[call_cntr].bandpath);
595  values[5] = UInt32GetDatum(bmd2[call_cntr].extbandnum);
596  }
597  else {
598  nulls[4] = TRUE;
599  nulls[5] = TRUE;
600  }
601 
602  /* build a tuple */
603  tuple = heap_form_tuple(tupdesc, values, nulls);
604 
605  /* make the tuple into a datum */
606  result = HeapTupleGetDatum(tuple);
607 
608  /* clean up */
609  pfree(bmd2[call_cntr].pixeltype);
610  if (bmd2[call_cntr].bandpath) pfree(bmd2[call_cntr].bandpath);
611 
612  SRF_RETURN_NEXT(funcctx, result);
613  }
614  /* do when there is no more left */
615  else {
616  pfree(bmd2);
617  SRF_RETURN_DONE(funcctx);
618  }
619 }
620 
625 Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS)
626 {
627  rt_pgraster *pgraster = NULL;
628  rt_pgraster *pgrtn = NULL;
629  rt_raster raster = NULL;
630  rt_band band = NULL;
631  double nodata;
632  int32_t bandindex;
633  bool forcechecking = FALSE;
634  bool skipset = FALSE;
635 
636  /* Deserialize raster */
637  if (PG_ARGISNULL(0))
638  PG_RETURN_NULL();
639  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
640 
641  /* Check index is not NULL or smaller than 1 */
642  if (PG_ARGISNULL(1))
643  bandindex = -1;
644  else
645  bandindex = PG_GETARG_INT32(1);
646  if (bandindex < 1) {
647  elog(NOTICE, "Invalid band index (must use 1-based). Nodata value not set. Returning original raster");
648  skipset = TRUE;
649  }
650 
651  raster = rt_raster_deserialize(pgraster, FALSE);
652  if (!raster) {
653  PG_FREE_IF_COPY(pgraster, 0);
654  elog(ERROR, "RASTER_setBandNoDataValue: Could not deserialize raster");
655  PG_RETURN_NULL();
656  }
657 
658  if (!skipset) {
659  /* Fetch requested band */
660  band = rt_raster_get_band(raster, bandindex - 1);
661  if (!band) {
662  elog(NOTICE, "Could not find raster band of index %d when setting pixel value. Nodata value not set. Returning original raster", bandindex);
663  }
664  else {
665  if (!PG_ARGISNULL(3))
666  forcechecking = PG_GETARG_BOOL(3);
667 
668  if (PG_ARGISNULL(2)) {
669  /* Set the hasnodata flag to FALSE */
671  POSTGIS_RT_DEBUGF(3, "Raster band %d does not have a nodata value", bandindex);
672  }
673  else {
674  /* Get the nodata value */
675  nodata = PG_GETARG_FLOAT8(2);
676 
677  /* Set the band's nodata value */
678  rt_band_set_nodata(band, nodata, NULL);
679 
680  /* Recheck all pixels if requested */
681  if (forcechecking)
683  }
684  }
685  }
686 
687  pgrtn = rt_raster_serialize(raster);
688  rt_raster_destroy(raster);
689  PG_FREE_IF_COPY(pgraster, 0);
690  if (!pgrtn)
691  PG_RETURN_NULL();
692 
693  SET_VARSIZE(pgrtn, pgrtn->size);
694  PG_RETURN_POINTER(pgrtn);
695 }
696 
701 Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS)
702 {
703  rt_pgraster *pgraster = NULL;
704  rt_pgraster *pgrtn = NULL;
705  rt_raster raster = NULL;
706  rt_band band = NULL;
707  int32_t bandindex;
708 
709  if (PG_ARGISNULL(0))
710  PG_RETURN_NULL();
711  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
712 
713  raster = rt_raster_deserialize(pgraster, FALSE);
714  if (!raster) {
715  PG_FREE_IF_COPY(pgraster, 0);
716  elog(ERROR, "RASTER_setBandIsNoData: Could not deserialize raster");
717  PG_RETURN_NULL();
718  }
719 
720  /* Check index is not NULL or smaller than 1 */
721  if (PG_ARGISNULL(1))
722  bandindex = -1;
723  else
724  bandindex = PG_GETARG_INT32(1);
725 
726  if (bandindex < 1)
727  elog(NOTICE, "Invalid band index (must use 1-based). Isnodata flag not set. Returning original raster");
728  else {
729  /* Fetch requested band */
730  band = rt_raster_get_band(raster, bandindex - 1);
731 
732  if (!band)
733  elog(NOTICE, "Could not find raster band of index %d. Isnodata flag not set. Returning original raster", bandindex);
734  else {
735  if (!rt_band_get_hasnodata_flag(band)) {
736  elog(NOTICE, "Band of index %d has no NODATA so cannot be NODATA. Returning original raster", bandindex);
737  }
738  /* Set the band's nodata value */
739  else {
740  rt_band_set_isnodata_flag(band, 1);
741  }
742  }
743  }
744 
745  /* Serialize raster again */
746  pgrtn = rt_raster_serialize(raster);
747  rt_raster_destroy(raster);
748  PG_FREE_IF_COPY(pgraster, 0);
749  if (!pgrtn) PG_RETURN_NULL();
750 
751  SET_VARSIZE(pgrtn, pgrtn->size);
752  PG_RETURN_POINTER(pgrtn);
753 }
754 
759 Datum RASTER_setBandPath(PG_FUNCTION_ARGS)
760 {
761  rt_pgraster *pgraster = NULL;
762  rt_pgraster *pgrtn = NULL;
763  rt_raster raster = NULL;
764  rt_band band = NULL;
765  int32_t bandindex = 1;
766  const char *outdbpathchar = NULL;
767  int32_t outdbindex = 1;
768  bool forceset = FALSE;
769  rt_band newband = NULL;
770 
771  int hasnodata;
772  double nodataval = 0.;
773 
774  if (PG_ARGISNULL(0))
775  PG_RETURN_NULL();
776  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
777 
778  raster = rt_raster_deserialize(pgraster, FALSE);
779  if (!raster) {
780  PG_FREE_IF_COPY(pgraster, 0);
781  elog(ERROR, "RASTER_setBandPath: Cannot deserialize raster");
782  PG_RETURN_NULL();
783  }
784 
785  /* Check index is not NULL or smaller than 1 */
786  if (!PG_ARGISNULL(1))
787  bandindex = PG_GETARG_INT32(1);
788 
789  if (bandindex < 1)
790  elog(NOTICE, "Invalid band index (must use 1-based). Returning original raster");
791  else {
792  /* Fetch requested band */
793  band = rt_raster_get_band(raster, bandindex - 1);
794 
795  if (!band)
796  elog(NOTICE, "Cannot find raster band of index %d. Returning original raster", bandindex);
797  else if (!rt_band_is_offline(band)) {
798  elog(NOTICE, "Band of index %d is not out-db. Returning original raster", bandindex);
799  }
800  else {
801  /* outdbpath */
802  if (!PG_ARGISNULL(2))
803  outdbpathchar = text_to_cstring(PG_GETARG_TEXT_P(2));
804  else
805  outdbpathchar = rt_band_get_ext_path(band);
806 
807  /* outdbindex, is 1-based */
808  if (!PG_ARGISNULL(3))
809  outdbindex = PG_GETARG_INT32(3);
810 
811  /* force */
812  if (!PG_ARGISNULL(4))
813  forceset = PG_GETARG_BOOL(4);
814 
815  hasnodata = rt_band_get_hasnodata_flag(band);
816  if (hasnodata)
817  rt_band_get_nodata(band, &nodataval);
818 
820  rt_raster_get_width(raster),
821  rt_raster_get_height(raster),
822  hasnodata,
823  nodataval,
824  outdbindex,
825  outdbpathchar,
826  forceset
827  );
828 
829  if (rt_raster_replace_band(raster, newband, bandindex - 1) == NULL)
830  elog(NOTICE, "Cannot change path of band. Returning original raster");
831  else
832  /* old band is in the variable band */
833  rt_band_destroy(band);
834  }
835  }
836 
837  /* Serialize raster again */
838  pgrtn = rt_raster_serialize(raster);
839  rt_raster_destroy(raster);
840  PG_FREE_IF_COPY(pgraster, 0);
841  if (!pgrtn) PG_RETURN_NULL();
842 
843  SET_VARSIZE(pgrtn, pgrtn->size);
844  PG_RETURN_POINTER(pgrtn);
845 }
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
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:325
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:195
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:685
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:336
#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:1682
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:359
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:1704
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:626
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:1502
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:372
void rt_band_set_hasnodata_flag(rt_band band, int flag)
Set hasnodata flag value.
Definition: rt_band.c:633
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:647
#define FALSE
Definition: dbfopen.c:168
Struct definitions.
Definition: librtcore.h:2230
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:583
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition: rt_band.c:666
Datum RASTER_setBandIsNoData(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:717