PostGIS  3.1.6dev-r@@SVN_REVISION@@
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 */
153 void _PG_init(void);
154 
155 /* Module unload callback */
156 void _PG_fini(void);
157 
158 #define RT_MSG_MAXLEN 256
159 
160 
161 /* ---------------------------------------------------------------- */
162 /* Memory allocation / error reporting hooks */
163 /* ---------------------------------------------------------------- */
164 
165 static void *
166 rt_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 
177 static void *
178 rt_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 
193 static void
194 rt_pg_free(void *ptr)
195 {
196  POSTGIS_RT_DEBUG(5, "rt_pfree called");
197  pfree(ptr);
198 }
199 
200 static void rt_pg_error(const char *fmt, va_list ap)
201  __attribute__(( format(printf,1,0) ));
202 
203 static void
204 rt_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 
214 static void rt_pg_notice(const char *fmt, va_list ap)
215  __attribute__(( format(printf,1,0) ));
216 
217 static void
218 rt_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 
228 static void rt_pg_debug(const char *fmt, va_list ap)
229  __attribute__(( format(printf,1,0) ));
230 
231 static void
232 rt_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 
247 static char *gdal_datapath = NULL;
248 extern char *gdal_enabled_drivers;
249 extern bool enable_outdb_rasters;
250 
251 /* ---------------------------------------------------------------- */
252 /* Useful variables */
253 /* ---------------------------------------------------------------- */
254 
258 
259 /* postgis.gdal_datapath */
260 static void
261 rtpg_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 */
277 static void
278 rtpg_assignHookGDALEnabledDrivers(const char *enabled_drivers, void *extra) {
279  int enable_all = 0;
280  int disable_all = 0;
281  int vsicurl = 0;
282 
283  char **enabled_drivers_array = NULL;
284  uint32_t enabled_drivers_count = 0;
285  bool *enabled_drivers_found = NULL;
286  char *gdal_skip = NULL;
287 
288  uint32_t i;
289  uint32_t j;
290 
291  POSTGIS_RT_DEBUGF(4, "GDAL_SKIP = %s", CPLGetConfigOption("GDAL_SKIP", ""));
292  POSTGIS_RT_DEBUGF(4, "enabled_drivers = %s", enabled_drivers);
293 
294  /* if NULL, nothing to do */
295  if (enabled_drivers == NULL)
296  return;
297 
298  elog(DEBUG4, "Enabling GDAL drivers: %s", enabled_drivers);
299 
300  /* destroy the driver manager */
301  /* this is the only way to ensure GDAL_SKIP is recognized */
302  GDALDestroyDriverManager();
303  CPLSetConfigOption("GDAL_SKIP", NULL);
304 
305  /* force wrapper function to call GDALAllRegister() */
307 
308  enabled_drivers_array = rtpg_strsplit(enabled_drivers, " ", &enabled_drivers_count);
309  enabled_drivers_found = palloc(sizeof(bool) * enabled_drivers_count);
310  memset(enabled_drivers_found, FALSE, sizeof(bool) * enabled_drivers_count);
311 
312  /* scan for keywords DISABLE_ALL and ENABLE_ALL */
313  disable_all = 0;
314  enable_all = 0;
315  if (strstr(enabled_drivers, GDAL_DISABLE_ALL) != NULL) {
316  for (i = 0; i < enabled_drivers_count; i++) {
317  if (strstr(enabled_drivers_array[i], GDAL_DISABLE_ALL) != NULL) {
318  enabled_drivers_found[i] = TRUE;
319  disable_all = 1;
320  }
321  }
322  }
323  else if (strstr(enabled_drivers, GDAL_ENABLE_ALL) != NULL) {
324  for (i = 0; i < enabled_drivers_count; i++) {
325  if (strstr(enabled_drivers_array[i], GDAL_ENABLE_ALL) != NULL) {
326  enabled_drivers_found[i] = TRUE;
327  enable_all = 1;
328  }
329  }
330  }
331  else if (strstr(enabled_drivers, GDAL_VSICURL) != NULL) {
332  for (i = 0; i < enabled_drivers_count; i++) {
333  if (strstr(enabled_drivers_array[i], GDAL_VSICURL) != NULL) {
334  enabled_drivers_found[i] = TRUE;
335  vsicurl = 1;
336  }
337  }
338  }
339 
340  if (!enable_all) {
341  int found = 0;
342  uint32_t drv_count = 0;
343  rt_gdaldriver drv_set = rt_raster_gdal_drivers(&drv_count, 0);
344 
345  POSTGIS_RT_DEBUGF(4, "driver count = %d", drv_count);
346 
347  /* all other drivers than those in new drivers are added to GDAL_SKIP */
348  for (i = 0; i < drv_count; i++) {
349  found = 0;
350 
351  if (!disable_all) {
352  /* gdal driver found in enabled_drivers, continue to thorough search */
353  if (strstr(enabled_drivers, drv_set[i].short_name) != NULL) {
354  /* thorough search of enabled_drivers */
355  for (j = 0; j < enabled_drivers_count; j++) {
356  /* driver found */
357  if (strcmp(enabled_drivers_array[j], drv_set[i].short_name) == 0) {
358  enabled_drivers_found[j] = TRUE;
359  found = 1;
360  }
361  }
362  }
363  }
364 
365  /* driver found, continue */
366  if (found)
367  continue;
368 
369  /* driver not found, add to gdal_skip */
370  if (gdal_skip == NULL) {
371  gdal_skip = palloc(sizeof(char) * (strlen(drv_set[i].short_name) + 1));
372  gdal_skip[0] = '\0';
373  }
374  else {
375  gdal_skip = repalloc(
376  gdal_skip,
377  sizeof(char) * (
378  strlen(gdal_skip) + 1 + strlen(drv_set[i].short_name) + 1
379  )
380  );
381  strcat(gdal_skip, " ");
382  }
383  strcat(gdal_skip, drv_set[i].short_name);
384  }
385 
386  for (i = 0; i < drv_count; i++) {
387  pfree(drv_set[i].short_name);
388  pfree(drv_set[i].long_name);
389  pfree(drv_set[i].create_options);
390  }
391  if (drv_count) pfree(drv_set);
392 
393  }
394 
395  for (i = 0; i < enabled_drivers_count; i++) {
396  if (enabled_drivers_found[i])
397  continue;
398 
399  if (disable_all)
400  elog(WARNING, "%s set. Ignoring GDAL driver: %s", GDAL_DISABLE_ALL, enabled_drivers_array[i]);
401  else if (enable_all)
402  elog(WARNING, "%s set. Ignoring GDAL driver: %s", GDAL_ENABLE_ALL, enabled_drivers_array[i]);
403  else
404  elog(WARNING, "Unknown GDAL driver: %s", enabled_drivers_array[i]);
405  }
406 
407  if (vsicurl)
408  elog(WARNING, "%s set.", GDAL_VSICURL);
409 
410  /* destroy the driver manager */
411  /* this is the only way to ensure GDAL_SKIP is recognized */
412  GDALDestroyDriverManager();
413 
414  /* set GDAL_SKIP */
415  POSTGIS_RT_DEBUGF(4, "gdal_skip = %s", gdal_skip);
416  CPLSetConfigOption("GDAL_SKIP", gdal_skip);
417  if (gdal_skip != NULL) pfree(gdal_skip);
418 
419  /* force wrapper function to call GDALAllRegister() */
421 
422  pfree(enabled_drivers_array);
423  pfree(enabled_drivers_found);
424  POSTGIS_RT_DEBUGF(4, "GDAL_SKIP = %s", CPLGetConfigOption("GDAL_SKIP", ""));
425 }
426 
427 /* postgis.enable_outdb_rasters */
428 static void
429 rtpg_assignHookEnableOutDBRasters(bool enable, void *extra) {
430  /* do nothing for now */
431 }
432 
433 /* Module load callback */
434 void
435 _PG_init(void) {
436 
437  bool boot_postgis_enable_outdb_rasters = false;
438  MemoryContext old_context;
439 
440  /*
441  * Change to context for memory allocation calls like palloc() in the
442  * extension initialization routine
443  */
444  old_context = MemoryContextSwitchTo(TopMemoryContext);
445 
446  /*
447  use POSTGIS_GDAL_ENABLED_DRIVERS to set the bootValue
448  of GUC postgis.gdal_enabled_drivers
449  */
450  env_postgis_gdal_enabled_drivers = getenv("POSTGIS_GDAL_ENABLED_DRIVERS");
451  if (env_postgis_gdal_enabled_drivers == NULL) {
452  size_t sz = sizeof(char) * (strlen(GDAL_DISABLE_ALL) + 1);
455  }
456  else {
459  );
460  }
462  4,
463  "boot_postgis_gdal_enabled_drivers = %s",
465  );
466 
467  /*
468  use POSTGIS_ENABLE_OUTDB_RASTERS to set the bootValue
469  of GUC postgis.enable_outdb_rasters
470  */
471  env_postgis_enable_outdb_rasters = getenv("POSTGIS_ENABLE_OUTDB_RASTERS");
472  if (env_postgis_enable_outdb_rasters != NULL) {
474 
475  /* out of memory */
476  if (env == NULL) {
477  elog(ERROR, "_PG_init: Cannot process environmental variable: POSTGIS_ENABLE_OUTDB_RASTERS");
478  return;
479  }
480 
481  if (strcmp(env, "1") == 0)
482  boot_postgis_enable_outdb_rasters = true;
483 
485  pfree(env);
486  }
488  4,
489  "boot_postgis_enable_outdb_rasters = %s",
490  boot_postgis_enable_outdb_rasters ? "TRUE" : "FALSE"
491  );
492 
493  /* Install liblwgeom handlers */
494  pg_install_lwgeom_handlers();
495 
496  /* Install rtcore handlers */
498 
499  /* Define custom GUC variables. */
500  if ( postgis_guc_find_option("postgis.gdal_datapath") )
501  {
502  /* In this narrow case the previously installed GUC is tied to the callback in */
503  /* the previously loaded library. Probably this is happening during an */
504  /* upgrade, so the old library is where the callback ties to. */
505  elog(WARNING, "'%s' is already set and cannot be changed until you reconnect", "postgis.gdal_datapath");
506  }
507  else
508  {
509  DefineCustomStringVariable(
510  "postgis.gdal_datapath", /* name */
511  "Path to GDAL data files.", /* short_desc */
512  "Physical path to directory containing GDAL data files (sets the GDAL_DATA config option).", /* long_desc */
513  &gdal_datapath, /* valueAddr */
514  NULL, /* bootValue */
515  PGC_SUSET, /* GucContext context */
516  0, /* int flags */
517  NULL, /* GucStringCheckHook check_hook */
518  rtpg_assignHookGDALDataPath, /* GucStringAssignHook assign_hook */
519  NULL /* GucShowHook show_hook */
520  );
521  }
522 
523  if ( postgis_guc_find_option("postgis.gdal_enabled_drivers") )
524  {
525  /* In this narrow case the previously installed GUC is tied to the callback in */
526  /* the previously loaded library. Probably this is happening during an */
527  /* upgrade, so the old library is where the callback ties to. */
528  elog(WARNING, "'%s' is already set and cannot be changed until you reconnect", "postgis.gdal_enabled_drivers");
529  }
530  else
531  {
532  DefineCustomStringVariable(
533  "postgis.gdal_enabled_drivers", /* name */
534  "Enabled GDAL drivers.", /* short_desc */
535  "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 */
536  &gdal_enabled_drivers, /* valueAddr */
537  boot_postgis_gdal_enabled_drivers, /* bootValue */
538  PGC_SUSET, /* GucContext context */
539  0, /* int flags */
540  NULL, /* GucStringCheckHook check_hook */
541  rtpg_assignHookGDALEnabledDrivers, /* GucStringAssignHook assign_hook */
542  NULL /* GucShowHook show_hook */
543  );
544  }
545 
546  if ( postgis_guc_find_option("postgis.enable_outdb_rasters") )
547  {
548  /* In this narrow case the previously installed GUC is tied to the callback in */
549  /* the previously loaded library. Probably this is happening during an */
550  /* upgrade, so the old library is where the callback ties to. */
551  elog(WARNING, "'%s' is already set and cannot be changed until you reconnect", "postgis.enable_outdb_rasters");
552  }
553  else
554  {
555  DefineCustomBoolVariable(
556  "postgis.enable_outdb_rasters", /* name */
557  "Enable Out-DB raster bands", /* short_desc */
558  "If true, rasters can access data located outside the database", /* long_desc */
559  &enable_outdb_rasters, /* valueAddr */
560  boot_postgis_enable_outdb_rasters, /* bootValue */
561  PGC_SUSET, /* GucContext context */
562  0, /* int flags */
563  NULL, /* GucStringCheckHook check_hook */
564  rtpg_assignHookEnableOutDBRasters, /* GucBoolAssignHook assign_hook */
565  NULL /* GucShowHook show_hook */
566  );
567  }
568 
569  /* Revert back to old context */
570  MemoryContextSwitchTo(old_context);
571 }
572 
573 /* Module unload callback */
574 void
575 _PG_fini(void) {
576 
577  MemoryContext old_context;
578 
579  old_context = MemoryContextSwitchTo(TopMemoryContext);
580 
581  /* Clean up */
585 
589 
590  /* Revert back to old context */
591  MemoryContextSwitchTo(old_context);
592 }
593 
594 
595 
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
#define TRUE
Definition: dbfopen.c:73
#define FALSE
Definition: dbfopen.c:72
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
#define GDAL_VSICURL
Definition: librtcore.h:2050
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
def fmt
Definition: pixval.py:93
char * rtpg_trim(const char *input)
char ** rtpg_strsplit(const char *str, const char *delimiter, uint32_t *n)
static char * env_postgis_enable_outdb_rasters
Definition: rtpostgis.c:257
static void * rt_pg_alloc(size_t size)
Definition: rtpostgis.c:166
void _PG_init(void)
Definition: rtpostgis.c:435
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:575
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_realloc(void *mem, size_t size)
Definition: rtpostgis.c:178
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:429
#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
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:61
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:65