PostGIS  3.3.9dev-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 <utils/builtins.h> /* for text_to_cstring() */
35 #include "utils/lsyscache.h" /* for get_typlenbyvalalign */
36 #include "utils/array.h" /* for ArrayType */
37 #include "catalog/pg_type.h" /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */
38 
39 #include "../../postgis_config.h"
40 
41 
42 #include "access/htup_details.h" /* for heap_form_tuple() */
43 
44 
45 #include "rtpostgis.h"
46 
47 extern bool enable_outdb_rasters;
48 
49 /* Get all the properties of a raster band */
50 Datum RASTER_getBandPixelType(PG_FUNCTION_ARGS);
51 Datum RASTER_getBandPixelTypeName(PG_FUNCTION_ARGS);
52 Datum RASTER_getBandNoDataValue(PG_FUNCTION_ARGS);
53 Datum RASTER_getBandPath(PG_FUNCTION_ARGS);
54 Datum RASTER_bandIsNoData(PG_FUNCTION_ARGS);
55 
56 /* get raster band's meta data */
57 Datum RASTER_bandmetadata(PG_FUNCTION_ARGS);
58 
59 /* Set all the properties of a raster band */
60 Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS);
61 Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS);
62 Datum RASTER_setBandPath(PG_FUNCTION_ARGS);
63 Datum RASTER_setBandIndex(PG_FUNCTION_ARGS);
64 
70 Datum RASTER_getBandPixelType(PG_FUNCTION_ARGS)
71 {
72  rt_pgraster *pgraster = NULL;
73  rt_raster raster = NULL;
74  rt_band band = NULL;
75  rt_pixtype pixtype;
76  int32_t bandindex;
77 
78  /* Deserialize raster */
79  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
80  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
81 
82  /* Index is 1-based */
83  bandindex = PG_GETARG_INT32(1);
84  if ( bandindex < 1 ) {
85  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
86  PG_FREE_IF_COPY(pgraster, 0);
87  PG_RETURN_NULL();
88  }
89 
90  raster = rt_raster_deserialize(pgraster, FALSE);
91  if ( ! raster ) {
92  PG_FREE_IF_COPY(pgraster, 0);
93  elog(ERROR, "RASTER_getBandPixelType: Could not deserialize raster");
94  PG_RETURN_NULL();
95  }
96 
97  /* Fetch requested band and its pixel type */
98  band = rt_raster_get_band(raster, bandindex - 1);
99  if ( ! band ) {
100  elog(NOTICE, "Could not find raster band of index %d when getting pixel type. Returning NULL", bandindex);
102  PG_FREE_IF_COPY(pgraster, 0);
103  PG_RETURN_NULL();
104  }
105 
106  pixtype = rt_band_get_pixtype(band);
107 
109  PG_FREE_IF_COPY(pgraster, 0);
110 
111  PG_RETURN_INT32(pixtype);
112 }
113 
120 Datum RASTER_getBandPixelTypeName(PG_FUNCTION_ARGS)
121 {
122  rt_pgraster *pgraster = NULL;
123  rt_raster raster = NULL;
124  rt_band band = NULL;
125  rt_pixtype pixtype;
126  int32_t bandindex;
127  const size_t name_size = 8; /* size of type name */
128  size_t size = 0;
129  char *ptr = NULL;
130  text *result = NULL;
131 
132  /* Deserialize raster */
133  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
134  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
135 
136  /* Index is 1-based */
137  bandindex = PG_GETARG_INT32(1);
138  if ( bandindex < 1 ) {
139  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
140  PG_FREE_IF_COPY(pgraster, 0);
141  PG_RETURN_NULL();
142  }
143 
144  raster = rt_raster_deserialize(pgraster, FALSE);
145  if ( ! raster ) {
146  PG_FREE_IF_COPY(pgraster, 0);
147  elog(ERROR, "RASTER_getBandPixelTypeName: Could not deserialize raster");
148  PG_RETURN_NULL();
149  }
150 
151  /* Fetch requested band and its pixel type */
152  band = rt_raster_get_band(raster, bandindex - 1);
153  if ( ! band ) {
154  elog(NOTICE, "Could not find raster band of index %d when getting pixel type name. Returning NULL", bandindex);
156  PG_FREE_IF_COPY(pgraster, 0);
157  PG_RETURN_NULL();
158  }
159 
160  pixtype = rt_band_get_pixtype(band);
161 
162  result = palloc(VARHDRSZ + name_size);
163  /* We don't need to check for NULL pointer, because if out of memory, palloc
164  * exit via elog(ERROR). It never returns NULL.
165  */
166 
167  memset(VARDATA(result), 0, name_size);
168  ptr = (char *)result + VARHDRSZ;
169  strcpy(ptr, rt_pixtype_name(pixtype));
170 
171  size = VARHDRSZ + strlen(ptr);
172  SET_VARSIZE(result, size);
173 
175  PG_FREE_IF_COPY(pgraster, 0);
176 
177  PG_RETURN_TEXT_P(result);
178 }
179 
185 Datum RASTER_getBandNoDataValue(PG_FUNCTION_ARGS)
186 {
187  rt_pgraster *pgraster = NULL;
188  rt_raster raster = NULL;
189  rt_band band = NULL;
190  int32_t bandindex;
191  double nodata;
192 
193  /* Deserialize raster */
194  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
195  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
196 
197  /* Index is 1-based */
198  bandindex = PG_GETARG_INT32(1);
199  if ( bandindex < 1 ) {
200  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
201  PG_FREE_IF_COPY(pgraster, 0);
202  PG_RETURN_NULL();
203  }
204 
205  raster = rt_raster_deserialize(pgraster, FALSE);
206  if ( ! raster ) {
207  PG_FREE_IF_COPY(pgraster, 0);
208  elog(ERROR, "RASTER_getBandNoDataValue: Could not deserialize raster");
209  PG_RETURN_NULL();
210  }
211 
212  /* Fetch requested band and its nodata value */
213  band = rt_raster_get_band(raster, bandindex - 1);
214  if ( ! band ) {
215  elog(NOTICE, "Could not find raster band of index %d when getting band nodata value. Returning NULL", bandindex);
217  PG_FREE_IF_COPY(pgraster, 0);
218  PG_RETURN_NULL();
219  }
220 
221  if ( ! rt_band_get_hasnodata_flag(band) ) {
222  /* Raster does not have a nodata value set so we return NULL */
224  PG_FREE_IF_COPY(pgraster, 0);
225  PG_RETURN_NULL();
226  }
227 
228  rt_band_get_nodata(band, &nodata);
229 
231  PG_FREE_IF_COPY(pgraster, 0);
232 
233  PG_RETURN_FLOAT8(nodata);
234 }
235 
236 
238 Datum RASTER_bandIsNoData(PG_FUNCTION_ARGS)
239 {
240  rt_pgraster *pgraster = NULL;
241  rt_raster raster = NULL;
242  rt_band band = NULL;
243  int32_t bandindex;
244  bool forcechecking = FALSE;
245  bool bandisnodata = FALSE;
246 
247  /* Index is 1-based */
248  bandindex = PG_GETARG_INT32(1);
249  if ( bandindex < 1 ) {
250  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
251  PG_RETURN_NULL();
252  }
253 
254  /* Deserialize raster */
255  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
256  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
257 
258  raster = rt_raster_deserialize(pgraster, FALSE);
259  if ( ! raster ) {
260  PG_FREE_IF_COPY(pgraster, 0);
261  elog(ERROR, "RASTER_bandIsNoData: Could not deserialize raster");
262  PG_RETURN_NULL();
263  }
264 
265  /* Fetch requested band and its nodata value */
266  band = rt_raster_get_band(raster, bandindex - 1);
267  if ( ! band ) {
268  elog(NOTICE, "Could not find raster band of index %d when determining if band is nodata. Returning NULL", bandindex);
270  PG_FREE_IF_COPY(pgraster, 0);
271  PG_RETURN_NULL();
272  }
273 
274  forcechecking = PG_GETARG_BOOL(2);
275 
276  bandisnodata = (forcechecking) ?
278 
280  PG_FREE_IF_COPY(pgraster, 0);
281 
282  PG_RETURN_BOOL(bandisnodata);
283 }
284 
289 Datum RASTER_getBandPath(PG_FUNCTION_ARGS)
290 {
291  rt_pgraster *pgraster = NULL;
292  rt_raster raster = NULL;
293  rt_band band = NULL;
294  int32_t bandindex;
295  const char *bandpath;
296  text *result;
297 
298  /* Index is 1-based */
299  bandindex = PG_GETARG_INT32(1);
300  if ( bandindex < 1 ) {
301  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
302  PG_RETURN_NULL();
303  }
304 
305  /* Deserialize raster */
306  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
307  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
308 
309  raster = rt_raster_deserialize(pgraster, FALSE);
310  if (!raster) {
311  PG_FREE_IF_COPY(pgraster, 0);
312  elog(ERROR, "RASTER_getBandPath: Could not deserialize raster");
313  PG_RETURN_NULL();
314  }
315 
316  /* Fetch requested band */
317  band = rt_raster_get_band(raster, bandindex - 1);
318  if (!band) {
319  elog(
320  NOTICE,
321  "Could not find raster band of index %d when getting band path. Returning NULL",
322  bandindex
323  );
325  PG_FREE_IF_COPY(pgraster, 0);
326  PG_RETURN_NULL();
327  }
328 
329  bandpath = rt_band_get_ext_path(band);
330  if (!bandpath) {
333  PG_FREE_IF_COPY(pgraster, 0);
334  PG_RETURN_NULL();
335  }
336 
337  result = cstring_to_text(bandpath);
338 
341  PG_FREE_IF_COPY(pgraster, 0);
342 
343  PG_RETURN_TEXT_P(result);
344 }
345 
346 
351 Datum RASTER_getBandFileSize(PG_FUNCTION_ARGS)
352 {
353  rt_pgraster *pgraster;
355  rt_band band = NULL;
356  int64_t fileSize;
357  int32_t bandindex;
358 
359  /* Index is 1-based */
360  bandindex = PG_GETARG_INT32(1);
361  if ( bandindex < 1 ) {
362  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
363  PG_RETURN_NULL();
364  }
365 
366  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
367  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
368 
369  raster = rt_raster_deserialize(pgraster, FALSE);
370  if ( ! raster ) {
371  PG_FREE_IF_COPY(pgraster, 0);
372  elog(ERROR, "RASTER_getFileSize: Could not deserialize raster");
373  PG_RETURN_NULL();
374  }
375 
376  /* Fetch requested band */
377  band = rt_raster_get_band(raster, bandindex - 1);
378  if (!band) {
379  elog(
380  NOTICE,
381  "Could not find raster band of index %d when getting band path. Returning NULL",
382  bandindex
383  );
385  PG_FREE_IF_COPY(pgraster, 0);
386  PG_RETURN_NULL();
387  }
388 
389  if (!rt_band_is_offline(band)) {
390  elog(NOTICE, "Band of index %d is not out-db.", bandindex);
393  PG_FREE_IF_COPY(pgraster, 0);
394  PG_RETURN_NULL();
395  }
396 
397  fileSize = rt_band_get_file_size(band);
398 
401  PG_FREE_IF_COPY(pgraster, 0);
402 
403  PG_RETURN_INT64(fileSize);
404 }
405 
410 Datum RASTER_getBandFileTimestamp(PG_FUNCTION_ARGS)
411 {
412  rt_pgraster *pgraster;
414  rt_band band = NULL;
415  int64_t fileSize;
416  int32_t bandindex;
417 
418  /* Index is 1-based */
419  bandindex = PG_GETARG_INT32(1);
420  if ( bandindex < 1 ) {
421  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
422  PG_RETURN_NULL();
423  }
424 
425  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
426  pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
427 
428  raster = rt_raster_deserialize(pgraster, FALSE);
429  if ( ! raster ) {
430  PG_FREE_IF_COPY(pgraster, 0);
431  elog(ERROR, "RASTER_getBandFileTimestamp: Could not deserialize raster");
432  PG_RETURN_NULL();
433  }
434 
435  /* Fetch requested band */
436  band = rt_raster_get_band(raster, bandindex - 1);
437  if (!band) {
438  elog(
439  NOTICE,
440  "Could not find raster band of index %d when getting band path. Returning NULL",
441  bandindex
442  );
444  PG_FREE_IF_COPY(pgraster, 0);
445  PG_RETURN_NULL();
446  }
447 
448  if (!rt_band_is_offline(band)) {
449  elog(NOTICE, "Band of index %d is not out-db.", bandindex);
452  PG_FREE_IF_COPY(pgraster, 0);
453  PG_RETURN_NULL();
454  }
455 
456  fileSize = rt_band_get_file_timestamp(band);
457 
460  PG_FREE_IF_COPY(pgraster, 0);
461 
462  PG_RETURN_INT64(fileSize);
463 }
464 
465 #define VALUES_LENGTH 8
466 
471 Datum RASTER_bandmetadata(PG_FUNCTION_ARGS)
472 {
473  FuncCallContext *funcctx;
474  TupleDesc tupdesc;
475  int call_cntr;
476  int max_calls;
477 
478  struct bandmetadata {
479  uint32_t bandnum;
480  char *pixeltype;
481  bool hasnodata;
482  double nodataval;
483  bool isoutdb;
484  char *bandpath;
485  uint8_t extbandnum;
486  uint64_t filesize;
487  uint64_t timestamp;
488  bool isnullband;
489  };
490  struct bandmetadata *bmd = NULL;
491  struct bandmetadata *bmd2 = NULL;
492 
493  HeapTuple tuple;
494  Datum result;
495 
496  if (SRF_IS_FIRSTCALL()) {
497  MemoryContext oldcontext;
498 
499  rt_pgraster *pgraster = NULL;
500  rt_raster raster = NULL;
501  rt_band band = NULL;
502 
503  ArrayType *array;
504  Oid etype;
505  Datum *e;
506  bool *nulls;
507  int16 typlen;
508  bool typbyval;
509  char typalign;
510  int i = 0;
511  int j = 0;
512  int n = 0;
513 
514  uint32_t numBands;
515  uint32_t idx = 1;
516  uint32_t *bandNums = NULL;
517  const char *chartmp = NULL;
518  size_t charlen;
519  uint8_t extbandnum;
520 
521  POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
522 
523  /* create a function context for cross-call persistence */
524  funcctx = SRF_FIRSTCALL_INIT();
525 
526  /* switch to memory context appropriate for multiple function calls */
527  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
528 
529  /* Build a tuple descriptor for our result type */
530  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
531  MemoryContextSwitchTo(oldcontext);
532  ereport(ERROR, (
533  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
534  errmsg(
535  "function returning record called in context "
536  "that cannot accept type record"
537  )
538  ));
539  }
540 
541  BlessTupleDesc(tupdesc);
542  funcctx->tuple_desc = tupdesc;
543 
544  /* pgraster is null, return null */
545  if (PG_ARGISNULL(0)) {
546  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata));
547  bmd->isnullband = TRUE;
548  funcctx->user_fctx = bmd;
549  funcctx->max_calls = 1;
550  MemoryContextSwitchTo(oldcontext);
551  goto PER_CALL;
552  }
553  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
554 
555  /* raster */
556  raster = rt_raster_deserialize(pgraster, FALSE);
557  if (!raster) {
558  PG_FREE_IF_COPY(pgraster, 0);
559  MemoryContextSwitchTo(oldcontext);
560  elog(ERROR, "RASTER_bandmetadata: Could not deserialize raster");
561  SRF_RETURN_DONE(funcctx);
562  }
563 
564  /* numbands */
565  numBands = rt_raster_get_num_bands(raster);
566  if (numBands < 1) {
567  elog(NOTICE, "Raster provided has no bands");
569  PG_FREE_IF_COPY(pgraster, 0);
570  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata));
571  bmd->isnullband = TRUE;
572  funcctx->user_fctx = bmd;
573  funcctx->max_calls = 1;
574  MemoryContextSwitchTo(oldcontext);
575  goto PER_CALL;
576  }
577 
578  /* band index */
579  array = PG_GETARG_ARRAYTYPE_P(1);
580  etype = ARR_ELEMTYPE(array);
581  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
582 
583  switch (etype) {
584  case INT2OID:
585  case INT4OID:
586  break;
587  default:
589  PG_FREE_IF_COPY(pgraster, 0);
590  MemoryContextSwitchTo(oldcontext);
591  elog(ERROR, "RASTER_bandmetadata: Invalid data type for band number(s)");
592  SRF_RETURN_DONE(funcctx);
593  break;
594  }
595 
596  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
597  &nulls, &n);
598 
599  bandNums = palloc(sizeof(uint32_t) * n);
600  for (i = 0, j = 0; i < n; i++) {
601  if (nulls[i]) continue;
602 
603  switch (etype) {
604  case INT2OID:
605  idx = (uint32_t) DatumGetInt16(e[i]);
606  break;
607  case INT4OID:
608  idx = (uint32_t) DatumGetInt32(e[i]);
609  break;
610  }
611 
612  POSTGIS_RT_DEBUGF(3, "band idx (before): %d", idx);
613  if (idx > numBands || idx < 1) {
614  elog(NOTICE, "Invalid band index: %d. Indices must be 1-based. Returning NULL", idx);
615  pfree(bandNums);
617  PG_FREE_IF_COPY(pgraster, 0);
618  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata));
619  bmd->isnullband = TRUE;
620  funcctx->user_fctx = bmd;
621  funcctx->max_calls = 1;
622  MemoryContextSwitchTo(oldcontext);
623  goto PER_CALL;
624  }
625 
626  bandNums[j] = idx;
627  POSTGIS_RT_DEBUGF(3, "bandNums[%d] = %d", j, bandNums[j]);
628  j++;
629  }
630 
631  if (j < 1) {
632  j = numBands;
633  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
634  for (i = 0; i < j; i++)
635  bandNums[i] = i + 1;
636  }
637  else if (j < n)
638  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
639 
640  bmd = (struct bandmetadata *) palloc0(sizeof(struct bandmetadata) * j);
641 
642  for (i = 0; i < j; i++) {
643  band = rt_raster_get_band(raster, bandNums[i] - 1);
644  if (NULL == band) {
645  elog(NOTICE, "Could not get raster band at index %d", bandNums[i]);
647  PG_FREE_IF_COPY(pgraster, 0);
648  bmd[0].isnullband = TRUE;
649  funcctx->user_fctx = bmd;
650  funcctx->max_calls = 1;
651  MemoryContextSwitchTo(oldcontext);
652  goto PER_CALL;
653  }
654 
655  /* bandnum */
656  bmd[i].bandnum = bandNums[i];
657 
658  /* pixeltype */
660  charlen = strlen(chartmp) + 1;
661  bmd[i].pixeltype = palloc(sizeof(char) * charlen);
662  strncpy(bmd[i].pixeltype, chartmp, charlen);
663 
664  /* hasnodatavalue */
666  bmd[i].hasnodata = TRUE;
667  else
668  bmd[i].hasnodata = FALSE;
669 
670  /* nodatavalue */
671  if (bmd[i].hasnodata)
672  rt_band_get_nodata(band, &(bmd[i].nodataval));
673  else
674  bmd[i].nodataval = 0;
675 
676  /* out-db path */
677  chartmp = rt_band_get_ext_path(band);
678  if (chartmp) {
679  charlen = strlen(chartmp) + 1;
680  bmd[i].bandpath = palloc(sizeof(char) * charlen);
681  strncpy(bmd[i].bandpath, chartmp, charlen);
682  }
683  else
684  bmd[i].bandpath = NULL;
685 
686  /* isoutdb */
687  bmd[i].isoutdb = bmd[i].bandpath ? TRUE : FALSE;
688 
689  /* out-db bandnum */
690  if (rt_band_get_ext_band_num(band, &extbandnum) == ES_NONE)
691  bmd[i].extbandnum = extbandnum + 1;
692  else
693  bmd[i].extbandnum = 0;
694 
695  bmd[i].filesize = 0;
696  bmd[i].timestamp = 0;
697  if( bmd[i].bandpath && enable_outdb_rasters ) {
698  VSIStatBufL sStat;
699  if( VSIStatL(bmd[i].bandpath, &sStat) == 0 ) {
700  bmd[i].filesize = sStat.st_size;
701  bmd[i].timestamp = sStat.st_mtime;
702  }
703  }
704 
706  }
707 
709  PG_FREE_IF_COPY(pgraster, 0);
710 
711  /* Store needed information */
712  funcctx->user_fctx = bmd;
713 
714  /* total number of tuples to be returned */
715  funcctx->max_calls = j;
716 
717  MemoryContextSwitchTo(oldcontext);
718  }
719 
720  PER_CALL:
721 
722  /* stuff done on every call of the function */
723  funcctx = SRF_PERCALL_SETUP();
724 
725  call_cntr = funcctx->call_cntr;
726  max_calls = funcctx->max_calls;
727  tupdesc = funcctx->tuple_desc;
728  bmd2 = funcctx->user_fctx;
729 
730  /* do when there is more left to send */
731  if (call_cntr < max_calls) {
732  Datum values[VALUES_LENGTH];
733  bool nulls[VALUES_LENGTH];
734 
735  if (bmd2[0].isnullband) {
736  int i;
737  for (i = 0; i < VALUES_LENGTH; i++)
738  nulls[i] = TRUE;
739  result = HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls));
740  SRF_RETURN_NEXT(funcctx, result);
741  }
742 
743  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
744 
745  values[0] = UInt32GetDatum(bmd2[call_cntr].bandnum);
746  values[1] = CStringGetTextDatum(bmd2[call_cntr].pixeltype);
747 
748  if (bmd2[call_cntr].hasnodata)
749  values[2] = Float8GetDatum(bmd2[call_cntr].nodataval);
750  else
751  nulls[2] = TRUE;
752 
753  values[3] = BoolGetDatum(bmd2[call_cntr].isoutdb);
754  if (bmd2[call_cntr].bandpath && strlen(bmd2[call_cntr].bandpath)) {
755  values[4] = CStringGetTextDatum(bmd2[call_cntr].bandpath);
756  values[5] = UInt32GetDatum(bmd2[call_cntr].extbandnum);
757  }
758  else {
759  nulls[4] = TRUE;
760  nulls[5] = TRUE;
761  }
762 
763  if (bmd2[call_cntr].filesize)
764  {
765  values[6] = UInt64GetDatum(bmd2[call_cntr].filesize);
766  values[7] = UInt64GetDatum(bmd2[call_cntr].timestamp);
767  }
768  else
769  {
770  nulls[6] = TRUE;
771  nulls[7] = TRUE;
772  }
773 
774  /* build a tuple */
775  tuple = heap_form_tuple(tupdesc, values, nulls);
776 
777  /* make the tuple into a datum */
778  result = HeapTupleGetDatum(tuple);
779 
780  /* clean up */
781  pfree(bmd2[call_cntr].pixeltype);
782  if (bmd2[call_cntr].bandpath) pfree(bmd2[call_cntr].bandpath);
783 
784  SRF_RETURN_NEXT(funcctx, result);
785  }
786  /* do when there is no more left */
787  else {
788  pfree(bmd2);
789  SRF_RETURN_DONE(funcctx);
790  }
791 }
792 
797 Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS)
798 {
799  rt_pgraster *pgraster = NULL;
800  rt_pgraster *pgrtn = NULL;
801  rt_raster raster = NULL;
802  rt_band band = NULL;
803  double nodata;
804  int32_t bandindex;
805  bool forcechecking = FALSE;
806  bool skipset = FALSE;
807 
808  /* Deserialize raster */
809  if (PG_ARGISNULL(0))
810  PG_RETURN_NULL();
811  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
812 
813  /* Check index is not NULL or smaller than 1 */
814  if (PG_ARGISNULL(1))
815  bandindex = -1;
816  else
817  bandindex = PG_GETARG_INT32(1);
818  if (bandindex < 1) {
819  elog(NOTICE, "Invalid band index (must use 1-based). Nodata value not set. Returning original raster");
820  skipset = TRUE;
821  }
822 
823  raster = rt_raster_deserialize(pgraster, FALSE);
824  if (!raster) {
825  PG_FREE_IF_COPY(pgraster, 0);
826  elog(ERROR, "RASTER_setBandNoDataValue: Could not deserialize raster");
827  PG_RETURN_NULL();
828  }
829 
830  if (!skipset) {
831  /* Fetch requested band */
832  band = rt_raster_get_band(raster, bandindex - 1);
833  if (!band) {
834  elog(NOTICE, "Could not find raster band of index %d when setting pixel value. Nodata value not set. Returning original raster", bandindex);
835  }
836  else {
837  if (!PG_ARGISNULL(3))
838  forcechecking = PG_GETARG_BOOL(3);
839 
840  if (PG_ARGISNULL(2)) {
841  /* Set the hasnodata flag to FALSE */
843  POSTGIS_RT_DEBUGF(3, "Raster band %d does not have a nodata value", bandindex);
844  }
845  else {
846  /* Get the nodata value */
847  nodata = PG_GETARG_FLOAT8(2);
848 
849  /* Set the band's nodata value */
850  rt_band_set_nodata(band, nodata, NULL);
851 
852  /* Recheck all pixels if requested */
853  if (forcechecking)
855  }
856  }
857  }
858 
859  pgrtn = rt_raster_serialize(raster);
861  PG_FREE_IF_COPY(pgraster, 0);
862  if (!pgrtn)
863  PG_RETURN_NULL();
864 
865  SET_VARSIZE(pgrtn, pgrtn->size);
866  PG_RETURN_POINTER(pgrtn);
867 }
868 
873 Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS)
874 {
875  rt_pgraster *pgraster = NULL;
876  rt_pgraster *pgrtn = NULL;
877  rt_raster raster = NULL;
878  rt_band band = NULL;
879  int32_t bandindex;
880 
881  if (PG_ARGISNULL(0))
882  PG_RETURN_NULL();
883  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
884 
885  raster = rt_raster_deserialize(pgraster, FALSE);
886  if (!raster) {
887  PG_FREE_IF_COPY(pgraster, 0);
888  elog(ERROR, "RASTER_setBandIsNoData: Could not deserialize raster");
889  PG_RETURN_NULL();
890  }
891 
892  /* Check index is not NULL or smaller than 1 */
893  if (PG_ARGISNULL(1))
894  bandindex = -1;
895  else
896  bandindex = PG_GETARG_INT32(1);
897 
898  if (bandindex < 1)
899  elog(NOTICE, "Invalid band index (must use 1-based). Isnodata flag not set. Returning original raster");
900  else {
901  /* Fetch requested band */
902  band = rt_raster_get_band(raster, bandindex - 1);
903 
904  if (!band)
905  elog(NOTICE, "Could not find raster band of index %d. Isnodata flag not set. Returning original raster", bandindex);
906  else {
908  elog(NOTICE, "Band of index %d has no NODATA so cannot be NODATA. Returning original raster", bandindex);
909  }
910  /* Set the band's nodata value */
911  else {
913  }
914  }
915  }
916 
917  /* Serialize raster again */
918  pgrtn = rt_raster_serialize(raster);
920  PG_FREE_IF_COPY(pgraster, 0);
921  if (!pgrtn) PG_RETURN_NULL();
922 
923  SET_VARSIZE(pgrtn, pgrtn->size);
924  PG_RETURN_POINTER(pgrtn);
925 }
926 
931 Datum RASTER_setBandPath(PG_FUNCTION_ARGS)
932 {
933  rt_pgraster *pgraster = NULL;
934  rt_pgraster *pgrtn = NULL;
935  rt_raster raster = NULL;
936  rt_band band = NULL;
937  int32_t bandindex = 1;
938  const char *outdbpathchar = NULL;
939  int32_t outdbindex = 1;
940  bool forceset = FALSE;
941  rt_band newband = NULL;
942 
943  int hasnodata;
944  double nodataval = 0.;
945 
946  if (PG_ARGISNULL(0))
947  PG_RETURN_NULL();
948  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
949 
950  raster = rt_raster_deserialize(pgraster, FALSE);
951  if (!raster) {
952  PG_FREE_IF_COPY(pgraster, 0);
953  elog(ERROR, "RASTER_setBandPath: Cannot deserialize raster");
954  PG_RETURN_NULL();
955  }
956 
957  /* Check index is not NULL or smaller than 1 */
958  if (!PG_ARGISNULL(1))
959  bandindex = PG_GETARG_INT32(1);
960 
961  if (bandindex < 1)
962  elog(NOTICE, "Invalid band index (must use 1-based). Returning original raster");
963  else {
964  /* Fetch requested band */
965  band = rt_raster_get_band(raster, bandindex - 1);
966 
967  if (!band)
968  elog(NOTICE, "Cannot find raster band of index %d. Returning original raster", bandindex);
969  else if (!rt_band_is_offline(band)) {
970  elog(NOTICE, "Band of index %d is not out-db. Returning original raster", bandindex);
971  }
972  else {
973  /* outdbpath */
974  if (!PG_ARGISNULL(2))
975  outdbpathchar = text_to_cstring(PG_GETARG_TEXT_P(2));
976  else
977  outdbpathchar = rt_band_get_ext_path(band);
978 
979  /* outdbindex, is 1-based */
980  if (!PG_ARGISNULL(3))
981  outdbindex = PG_GETARG_INT32(3);
982 
983  /* force */
984  if (!PG_ARGISNULL(4))
985  forceset = PG_GETARG_BOOL(4);
986 
987  hasnodata = rt_band_get_hasnodata_flag(band);
988  if (hasnodata)
989  rt_band_get_nodata(band, &nodataval);
990 
994  hasnodata,
995  nodataval,
996  outdbindex,
997  outdbpathchar,
998  forceset
999  );
1000 
1001  if (rt_raster_replace_band(raster, newband, bandindex - 1) == NULL)
1002  elog(NOTICE, "Cannot change path of band. Returning original raster");
1003  else
1004  /* old band is in the variable band */
1006  }
1007  }
1008 
1009  /* Serialize raster again */
1010  pgrtn = rt_raster_serialize(raster);
1012  PG_FREE_IF_COPY(pgraster, 0);
1013  if (!pgrtn) PG_RETURN_NULL();
1014 
1015  SET_VARSIZE(pgrtn, pgrtn->size);
1016  PG_RETURN_POINTER(pgrtn);
1017 }
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:681
rt_errorstate rt_band_set_isnodata_flag(rt_band band, int flag)
Set isnodata flag value.
Definition: rt_band.c:695
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
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:86
rt_pixtype
Definition: librtcore.h:187
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition: rt_band.c:714
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
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:1526
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:1909
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:182
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: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: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:1887
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:631
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition: rt_pixel.c:110
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:125
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.
Definition: rt_serialize.c:725
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:385
band
Definition: ovdump.py:58
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
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:69
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:73
Struct definitions.
Definition: librtcore.h:2396