PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
rtpostgis.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/***************************************************************
31 * Some rules for returning NOTICE or ERROR...
32 *
33 * Send an ERROR like:
34 *
35 * elog(ERROR, "RASTER_out: Could not deserialize raster");
36 *
37 * only when:
38 *
39 * -something wrong happen with memory,
40 * -a function got an invalid argument ('3BUI' as pixel type) so that no row can
41 * be processed
42 *
43 * *** IMPORTANT: elog(ERROR, ...) does NOT return to calling function ***
44 *
45 * Send a NOTICE like:
46 *
47 * elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
48 *
49 * when arguments (e.g. x, y, band) are NULL or out of range so that some or
50 * most rows can be processed anyway
51 *
52 * in this case,
53 * for SET functions or function normally returning a modified raster, return
54 * the original raster
55 * for GET functions, return NULL
56 * try to deduce a valid parameter value if it makes sence (e.g. out of range
57 * index for addBand)
58 *
59 * Do not put the name of the faulty function for NOTICEs, only with ERRORs.
60 *
61 ****************************************************************/
62
63/******************************************************************************
64 * Some notes on memory management...
65 *
66 * Every time a SQL function is called, PostgreSQL creates a new memory context.
67 * So, all the memory allocated with palloc/repalloc in that context is
68 * automatically free'd at the end of the function. If you want some data to
69 * live between function calls, you have 2 options:
70 *
71 * - Use fcinfo->flinfo->fn_mcxt contex to store the data (by pointing the
72 * data you want to keep with fcinfo->flinfo->fn_extra)
73 * - Use SRF funcapi, and storing the data at multi_call_memory_ctx (by pointing
74 * the data you want to keep with funcctx->user_fctx. funcctx is created by
75 * funcctx = SPI_FIRSTCALL_INIT()). Recommended way in functions returning rows,
76 * like RASTER_dumpAsPolygons (see section 34.9.9 at
77 * http://www.postgresql.org/docs/8.4/static/xfunc-c.html).
78 *
79 * But raster code follows the same philosophy than the rest of PostGIS: keep
80 * memory as clean as possible. So, we free all allocated memory.
81 *
82 * TODO: In case of functions returning NULL, we should free the memory too.
83 *****************************************************************************/
84
85/******************************************************************************
86 * Notes for use of PG_DETOAST_DATUM(), PG_DETOAST_DATUM_SLICE()
87 * and PG_DETOAST_DATUM_COPY()
88 *
89 * When ONLY getting raster (not band) metadata, use PG_DETOAST_DATUM_SLICE()
90 * as it is generally quicker to get only the chunk of memory that contains
91 * the raster metadata.
92 *
93 * Example: PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(0), 0,
94 * sizeof(struct rt_raster_serialized_t))
95 *
96 * When ONLY setting raster or band(s) metadata OR reading band data, use
97 * PG_DETOAST_DATUM() as rt_raster_deserialize() allocates local memory
98 * for the raster and band(s) metadata.
99 *
100 * Example: PG_DETOAST_DATUM(PG_GETARG_DATUM(0))
101 *
102 * When SETTING band pixel values, use PG_DETOAST_DATUM_COPY(). This is
103 * because band data (not metadata) is just a pointer to the correct
104 * memory location in the detoasted datum. What is returned from
105 * PG_DETOAST_DATUM() may or may not be a copy of the input datum.
106 *
107 * From the comments in postgresql/src/include/fmgr.h...
108 *
109 * pg_detoast_datum() gives you either the input datum (if not toasted)
110 * or a detoasted copy allocated with palloc().
111 *
112 * From the mouth of Tom Lane...
113 * http://archives.postgresql.org/pgsql-hackers/2002-01/msg01289.php
114 *
115 * PG_DETOAST_DATUM_COPY guarantees to give you a copy, even if the
116 * original wasn't toasted. This allows you to scribble on the input,
117 * in case that happens to be a useful way of forming your result.
118 * Without a forced copy, a routine for a pass-by-ref datatype must
119 * NEVER, EVER scribble on its input ... because very possibly it'd
120 * be scribbling on a valid tuple in a disk buffer, or a valid entry
121 * in the syscache.
122 *
123 * The key detail above is that the raster datatype is a varlena, a
124 * passed by reference datatype.
125 *
126 * Example: PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))
127 *
128 * If in doubt, use PG_DETOAST_DATUM_COPY() as that guarantees that the input
129 * datum is copied for use.
130 *****************************************************************************/
131
132#include <postgres.h> /* for palloc */
133#include <fmgr.h> /* for PG_MODULE_MAGIC */
134#include "utils/guc.h"
135#include "utils/memutils.h"
136
137#include "../../postgis_config.h"
138#include "lwgeom_pg.h"
139
140#include "rtpostgis.h"
141#include "rtpg_internal.h"
142
143#ifndef __GNUC__
144# define __attribute__ (x)
145#endif
146
147/*
148 * This is required for builds against pgsql
149 */
151
152/* Module load callback */
153void _PG_init(void);
154
155/* Module unload callback */
156void _PG_fini(void);
157
158#define RT_MSG_MAXLEN 256
159
160
161/* ---------------------------------------------------------------- */
162/* Memory allocation / error reporting hooks */
163/* ---------------------------------------------------------------- */
164
165static void *
166rt_pg_alloc(size_t size)
167{
168 void * result;
169
170 POSTGIS_RT_DEBUGF(5, "rt_pgalloc(%ld) called", (long int) size);
171
172 result = palloc(size);
173
174 return result;
175}
176
177static void *
178rt_pg_realloc(void *mem, size_t size)
179{
180 void * result;
181
182 POSTGIS_RT_DEBUGF(5, "rt_pg_realloc(%ld) called", (long int) size);
183
184 if (mem)
185 result = repalloc(mem, size);
186
187 else
188 result = palloc(size);
189
190 return result;
191}
192
193static void
194rt_pg_free(void *ptr)
195{
196 POSTGIS_RT_DEBUG(5, "rt_pfree called");
197 pfree(ptr);
198}
199
200static void rt_pg_error(const char *fmt, va_list ap)
201 __attribute__(( format(printf,1,0) ));
202
203static void
204rt_pg_error(const char *fmt, va_list ap)
205{
206 char errmsg[RT_MSG_MAXLEN+1];
207
208 vsnprintf (errmsg, RT_MSG_MAXLEN, fmt, ap);
209
210 errmsg[RT_MSG_MAXLEN]='\0';
211 ereport(ERROR, (errmsg_internal("%s", errmsg)));
212}
213
214static void rt_pg_notice(const char *fmt, va_list ap)
215 __attribute__(( format(printf,1,0) ));
216
217static void
218rt_pg_notice(const char *fmt, va_list ap)
219{
220 char msg[RT_MSG_MAXLEN+1];
221
222 vsnprintf (msg, RT_MSG_MAXLEN, fmt, ap);
223
224 msg[RT_MSG_MAXLEN]='\0';
225 ereport(NOTICE, (errmsg_internal("%s", msg)));
226}
227
228static void rt_pg_debug(const char *fmt, va_list ap)
229 __attribute__(( format(printf,1,0) ));
230
231static void
232rt_pg_debug(const char *fmt, va_list ap)
233{
234 char msg[RT_MSG_MAXLEN+1];
235
236 vsnprintf (msg, RT_MSG_MAXLEN, fmt, ap);
237
238 msg[RT_MSG_MAXLEN]='\0';
239 ereport(DEBUG1, (errmsg_internal("%s", msg)));
240}
241
242
243/* ---------------------------------------------------------------- */
244/* PostGIS raster GUCs */
245/* ---------------------------------------------------------------- */
246
247static char *gdal_datapath = NULL;
248extern char *gdal_enabled_drivers;
249extern bool enable_outdb_rasters;
250
251/* ---------------------------------------------------------------- */
252/* Useful variables */
253/* ---------------------------------------------------------------- */
254
258
259/* postgis.gdal_datapath */
260static void
261rtpg_assignHookGDALDataPath(const char *newpath, void *extra) {
262 POSTGIS_RT_DEBUGF(4, "newpath = %s", newpath);
263 POSTGIS_RT_DEBUGF(4, "gdaldatapath = %s", gdal_datapath);
264
265 /* clear finder cache */
266 CPLFinderClean();
267
268 /* clear cached OSR */
269 OSRCleanup();
270
271 /* set GDAL_DATA */
272 CPLSetConfigOption("GDAL_DATA", newpath);
273 POSTGIS_RT_DEBUGF(4, "GDAL_DATA = %s", CPLGetConfigOption("GDAL_DATA", ""));
274}
275
276/* postgis.gdal_enabled_drivers */
277static void
278rtpg_assignHookGDALEnabledDrivers(const char *enabled_drivers, void *extra) {
279 int enable_all = 0;
280 int disable_all = 0;
281
282 char **enabled_drivers_array = NULL;
283 uint32_t enabled_drivers_count = 0;
284 bool *enabled_drivers_found = NULL;
285 char *gdal_skip = NULL;
286
287 uint32_t i;
288 uint32_t j;
289
290 POSTGIS_RT_DEBUGF(4, "GDAL_SKIP = %s", CPLGetConfigOption("GDAL_SKIP", ""));
291 POSTGIS_RT_DEBUGF(4, "enabled_drivers = %s", enabled_drivers);
292
293 /* if NULL, nothing to do */
294 if (enabled_drivers == NULL)
295 return;
296
297 /* destroy the driver manager */
298 /* this is the only way to ensure GDAL_SKIP is recognized */
299 GDALDestroyDriverManager();
300 CPLSetConfigOption("GDAL_SKIP", NULL);
301
302 /* force wrapper function to call GDALAllRegister() */
304
305 enabled_drivers_array = rtpg_strsplit(enabled_drivers, " ", &enabled_drivers_count);
306 enabled_drivers_found = palloc(sizeof(bool) * enabled_drivers_count);
307 memset(enabled_drivers_found, FALSE, sizeof(bool) * enabled_drivers_count);
308
309 /* scan for keywords DISABLE_ALL and ENABLE_ALL */
310 disable_all = 0;
311 enable_all = 0;
312 if (strstr(enabled_drivers, GDAL_DISABLE_ALL) != NULL) {
313 for (i = 0; i < enabled_drivers_count; i++) {
314 if (strstr(enabled_drivers_array[i], GDAL_DISABLE_ALL) != NULL) {
315 enabled_drivers_found[i] = TRUE;
316 disable_all = 1;
317 }
318 }
319 }
320 else if (strstr(enabled_drivers, GDAL_ENABLE_ALL) != NULL) {
321 for (i = 0; i < enabled_drivers_count; i++) {
322 if (strstr(enabled_drivers_array[i], GDAL_ENABLE_ALL) != NULL) {
323 enabled_drivers_found[i] = TRUE;
324 enable_all = 1;
325 }
326 }
327 }
328
329 if (!enable_all) {
330 int found = 0;
331 uint32_t drv_count = 0;
332 rt_gdaldriver drv_set = rt_raster_gdal_drivers(&drv_count, 0);
333
334 POSTGIS_RT_DEBUGF(4, "driver count = %d", drv_count);
335
336 /* all other drivers than those in new drivers are added to GDAL_SKIP */
337 for (i = 0; i < drv_count; i++) {
338 found = 0;
339
340 if (!disable_all) {
341 /* gdal driver found in enabled_drivers, continue to thorough search */
342 if (strstr(enabled_drivers, drv_set[i].short_name) != NULL) {
343 /* thorough search of enabled_drivers */
344 for (j = 0; j < enabled_drivers_count; j++) {
345 /* driver found */
346 if (strcmp(enabled_drivers_array[j], drv_set[i].short_name) == 0) {
347 enabled_drivers_found[j] = TRUE;
348 found = 1;
349 }
350 }
351 }
352 }
353
354 /* driver found, continue */
355 if (found)
356 continue;
357
358 /* driver not found, add to gdal_skip */
359 if (gdal_skip == NULL) {
360 gdal_skip = palloc(sizeof(char) * (strlen(drv_set[i].short_name) + 1));
361 gdal_skip[0] = '\0';
362 }
363 else {
364 gdal_skip = repalloc(
365 gdal_skip,
366 sizeof(char) * (
367 strlen(gdal_skip) + 1 + strlen(drv_set[i].short_name) + 1
368 )
369 );
370 strcat(gdal_skip, " ");
371 }
372 strcat(gdal_skip, drv_set[i].short_name);
373 }
374
375 for (i = 0; i < drv_count; i++) {
376 pfree(drv_set[i].short_name);
377 pfree(drv_set[i].long_name);
378 pfree(drv_set[i].create_options);
379 }
380 if (drv_count) pfree(drv_set);
381
382 }
383
384 for (i = 0; i < enabled_drivers_count; i++) {
385 if (enabled_drivers_found[i])
386 continue;
387
388 if (disable_all)
389 elog(WARNING, "%s set. Ignoring GDAL driver: %s", GDAL_DISABLE_ALL, enabled_drivers_array[i]);
390 else if (enable_all)
391 elog(WARNING, "%s set. Ignoring GDAL driver: %s", GDAL_ENABLE_ALL, enabled_drivers_array[i]);
392 else
393 elog(WARNING, "Unknown GDAL driver: %s", enabled_drivers_array[i]);
394 }
395
396 /* destroy the driver manager */
397 /* this is the only way to ensure GDAL_SKIP is recognized */
398 GDALDestroyDriverManager();
399
400 /* set GDAL_SKIP */
401 POSTGIS_RT_DEBUGF(4, "gdal_skip = %s", gdal_skip);
402 CPLSetConfigOption("GDAL_SKIP", gdal_skip);
403 if (gdal_skip != NULL) pfree(gdal_skip);
404
405 /* force wrapper function to call GDALAllRegister() */
407
408 pfree(enabled_drivers_array);
409 pfree(enabled_drivers_found);
410 POSTGIS_RT_DEBUGF(4, "GDAL_SKIP = %s", CPLGetConfigOption("GDAL_SKIP", ""));
411}
412
413/* postgis.enable_outdb_rasters */
414static void
415rtpg_assignHookEnableOutDBRasters(bool enable, void *extra) {
416 /* do nothing for now */
417}
418
419/* Module load callback */
420void
421_PG_init(void) {
422
423 bool boot_postgis_enable_outdb_rasters = false;
424 MemoryContext old_context;
425
426 /*
427 * Change to context for memory allocation calls like palloc() in the
428 * extension initialization routine
429 */
430 old_context = MemoryContextSwitchTo(TopMemoryContext);
431
432 /*
433 use POSTGIS_GDAL_ENABLED_DRIVERS to set the bootValue
434 of GUC postgis.gdal_enabled_drivers
435 */
436 env_postgis_gdal_enabled_drivers = getenv("POSTGIS_GDAL_ENABLED_DRIVERS");
438 size_t sz = sizeof(char) * (strlen(GDAL_DISABLE_ALL) + 1);
441 }
442 else {
445 );
446 }
448 4,
449 "boot_postgis_gdal_enabled_drivers = %s",
451 );
452
453 /*
454 use POSTGIS_ENABLE_OUTDB_RASTERS to set the bootValue
455 of GUC postgis.enable_outdb_rasters
456 */
457 env_postgis_enable_outdb_rasters = getenv("POSTGIS_ENABLE_OUTDB_RASTERS");
460
461 /* out of memory */
462 if (env == NULL) {
463 elog(ERROR, "_PG_init: Cannot process environmental variable: POSTGIS_ENABLE_OUTDB_RASTERS");
464 return;
465 }
466
467 if (strcmp(env, "1") == 0)
468 boot_postgis_enable_outdb_rasters = true;
469
471 pfree(env);
472 }
474 4,
475 "boot_postgis_enable_outdb_rasters = %s",
476 boot_postgis_enable_outdb_rasters ? "TRUE" : "FALSE"
477 );
478
479 /* Install liblwgeom handlers */
480 pg_install_lwgeom_handlers();
481
482 /* Install rtcore handlers */
484
485 /* Define custom GUC variables. */
486 if ( postgis_guc_find_option("postgis.gdal_datapath") )
487 {
488 /* In this narrow case the previously installed GUC is tied to the callback in */
489 /* the previously loaded library. Probably this is happening during an */
490 /* upgrade, so the old library is where the callback ties to. */
491 elog(WARNING, "'%s' is already set and cannot be changed until you reconnect", "postgis.gdal_datapath");
492 }
493 else
494 {
495 DefineCustomStringVariable(
496 "postgis.gdal_datapath", /* name */
497 "Path to GDAL data files.", /* short_desc */
498 "Physical path to directory containing GDAL data files (sets the GDAL_DATA config option).", /* long_desc */
499 &gdal_datapath, /* valueAddr */
500 NULL, /* bootValue */
501 PGC_SUSET, /* GucContext context */
502 0, /* int flags */
503 NULL, /* GucStringCheckHook check_hook */
504 rtpg_assignHookGDALDataPath, /* GucStringAssignHook assign_hook */
505 NULL /* GucShowHook show_hook */
506 );
507 }
508
509 if ( postgis_guc_find_option("postgis.gdal_enabled_drivers") )
510 {
511 /* In this narrow case the previously installed GUC is tied to the callback in */
512 /* the previously loaded library. Probably this is happening during an */
513 /* upgrade, so the old library is where the callback ties to. */
514 elog(WARNING, "'%s' is already set and cannot be changed until you reconnect", "postgis.gdal_enabled_drivers");
515 }
516 else
517 {
518 DefineCustomStringVariable(
519 "postgis.gdal_enabled_drivers", /* name */
520 "Enabled GDAL drivers.", /* short_desc */
521 "List of enabled GDAL drivers by short name. To enable/disable all drivers, use 'ENABLE_ALL' or 'DISABLE_ALL' (sets the GDAL_SKIP config option).", /* long_desc */
522 &gdal_enabled_drivers, /* valueAddr */
523 boot_postgis_gdal_enabled_drivers, /* bootValue */
524 PGC_SUSET, /* GucContext context */
525 0, /* int flags */
526 NULL, /* GucStringCheckHook check_hook */
527 rtpg_assignHookGDALEnabledDrivers, /* GucStringAssignHook assign_hook */
528 NULL /* GucShowHook show_hook */
529 );
530 }
531
532 if ( postgis_guc_find_option("postgis.enable_outdb_rasters") )
533 {
534 /* In this narrow case the previously installed GUC is tied to the callback in */
535 /* the previously loaded library. Probably this is happening during an */
536 /* upgrade, so the old library is where the callback ties to. */
537 elog(WARNING, "'%s' is already set and cannot be changed until you reconnect", "postgis.enable_outdb_rasters");
538 }
539 else
540 {
541 DefineCustomBoolVariable(
542 "postgis.enable_outdb_rasters", /* name */
543 "Enable Out-DB raster bands", /* short_desc */
544 "If true, rasters can access data located outside the database", /* long_desc */
545 &enable_outdb_rasters, /* valueAddr */
546 boot_postgis_enable_outdb_rasters, /* bootValue */
547 PGC_SUSET, /* GucContext context */
548 0, /* int flags */
549 NULL, /* GucStringCheckHook check_hook */
550 rtpg_assignHookEnableOutDBRasters, /* GucBoolAssignHook assign_hook */
551 NULL /* GucShowHook show_hook */
552 );
553 }
554
555 /* Revert back to old context */
556 MemoryContextSwitchTo(old_context);
557}
558
559/* Module unload callback */
560void
561_PG_fini(void) {
562
563 MemoryContext old_context;
564
565 old_context = MemoryContextSwitchTo(TopMemoryContext);
566
567 /* Clean up */
571
575
576 /* Revert back to old context */
577 MemoryContextSwitchTo(old_context);
578}
579
580
581
#define TRUE
Definition dbfopen.c:169
#define FALSE
Definition dbfopen.c:168
int rt_util_gdal_register_all(int force_register_all)
Definition rt_util.c:338
rt_gdaldriver rt_raster_gdal_drivers(uint32_t *drv_count, uint8_t cancc)
Returns a set of available GDAL drivers.
Definition rt_raster.c:1711
#define GDAL_ENABLE_ALL
Definition librtcore.h:2048
#define GDAL_DISABLE_ALL
Definition librtcore.h:2049
void rt_set_handlers(rt_allocator allocator, rt_reallocator reallocator, rt_deallocator deallocator, rt_message_handler error_handler, rt_message_handler info_handler, rt_message_handler warning_handler)
This function is called when the PostgreSQL backend is taking care of the memory and we want to use p...
Definition rt_context.c:151
char ** rtpg_strsplit(const char *str, const char *delimiter, uint32_t *n)
char * rtpg_trim(const char *input)
static void * rt_pg_alloc(size_t size)
Definition rtpostgis.c:166
static char * env_postgis_enable_outdb_rasters
Definition rtpostgis.c:257
void _PG_init(void)
Definition rtpostgis.c:421
PG_MODULE_MAGIC
Definition rtpostgis.c:150
static void rtpg_assignHookGDALDataPath(const char *newpath, void *extra)
Definition rtpostgis.c:261
static void rt_pg_error(const char *fmt, va_list ap) __attribute__((format(printf
Definition rtpostgis.c:204
void _PG_fini(void)
Definition rtpostgis.c:561
bool enable_outdb_rasters
Definition rt_band.c:417
static void rt_pg_notice(const char *fmt, va_list ap) __attribute__((format(printf
Definition rtpostgis.c:218
static char * env_postgis_gdal_enabled_drivers
Definition rtpostgis.c:255
static char * boot_postgis_gdal_enabled_drivers
Definition rtpostgis.c:256
#define RT_MSG_MAXLEN
Definition rtpostgis.c:158
static void rtpg_assignHookGDALEnabledDrivers(const char *enabled_drivers, void *extra)
Definition rtpostgis.c:278
static void rt_pg_free(void *ptr)
Definition rtpostgis.c:194
char * gdal_enabled_drivers
Definition rt_util.c:377
static void rtpg_assignHookEnableOutDBRasters(bool enable, void *extra)
Definition rtpostgis.c:415
#define __attribute__
Definition rtpostgis.c:144
static void rt_pg_debug(const char *fmt, va_list ap) __attribute__((format(printf
Definition rtpostgis.c:232
static char * gdal_datapath
Definition rtpostgis.c:247
static void * rt_pg_realloc(void *mem, size_t size)
Definition rtpostgis.c:178
#define POSTGIS_RT_DEBUG(level, msg)
Definition rtpostgis.h:61
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition rtpostgis.h:65