PostGIS  3.0.6dev-r@@SVN_REVISION@@
raster2pgsql.c
Go to the documentation of this file.
1 /*
2  *
3  * PostGIS raster loader
4  * http://trac.osgeo.org/postgis/wiki/WKTRaster
5  *
6  * Copyright 2001-2003 Refractions Research Inc.
7  * Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
8  * Copyright 2009 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
9  * Copyright (C) 2011 Regents of the University of California
10  * <bkpark@ucdavis.edu>
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "raster2pgsql.h"
29 #include "gdal_vrt.h"
30 #include "ogr_srs_api.h"
31 #include <assert.h>
32 
33 #define xstr(s) str(s)
34 #define str(s) #s
35 
36 static void
37 loader_rt_error_handler(const char *fmt, va_list ap) {
38  static const char *label = "ERROR: ";
39  char newfmt[1024] = {0};
40  snprintf(newfmt, 1024, "%s%s\n", label, fmt);
41  newfmt[1023] = '\0';
42  vfprintf(stderr, newfmt, ap);
43  va_end(ap);
44 }
45 
46 static void
47 loader_rt_warning_handler(const char *fmt, va_list ap) {
48  static const char *label = "WARNING: ";
49  char newfmt[1024] = {0};
50  snprintf(newfmt, 1024, "%s%s\n", label, fmt);
51  newfmt[1023] = '\0';
52  vfprintf(stderr, newfmt, ap);
53  va_end(ap);
54 }
55 
56 static void
57 loader_rt_info_handler(const char *fmt, va_list ap) {
58  static const char *label = "INFO: ";
59  char newfmt[1024] = {0};
60  snprintf(newfmt, 1024, "%s%s\n", label, fmt);
61  newfmt[1023] = '\0';
62  vfprintf(stderr, newfmt, ap);
63  va_end(ap);
64 }
65 
66 static void
75  );
76 }
77 
78 static void
80  uint16_t i;
81  uint16_t nbands = rt_raster_get_num_bands(raster);
82  for (i = 0; i < nbands; i++) {
84  if (band == NULL) continue;
85 
87  void* mem = rt_band_get_data(band);
88  if (mem) rtdealloc(mem);
89  }
91  }
93 }
94 
95 static int
96 array_range(int min, int max, int step, int **range, uint32_t *len) {
97  int i = 0;
98  int j = 0;
99 
100  step = abs(step);
101  *len = (uint32_t) ((abs(max - min) + 1 + (step / 2)) / step);
102  *range = rtalloc(sizeof(int) * *len);
103 
104  if (min < max) {
105  for (i = min, j = 0; i <= max; i += step, j++)
106  (*range)[j] = i;
107  }
108  else if (max < min) {
109  if (step > 0) step *= -1;
110  for (i = min, j = 0; i >= max; i += step, j++)
111  (*range)[j] = i;
112  }
113  else if (min == max) {
114  (*range)[0] = min;
115  }
116  else {
117  *len = 0;
118  *range = NULL;
119  return 0;
120  }
121 
122  return 1;
123 }
124 
125 /* string replacement function taken from
126  * http://ubuntuforums.org/showthread.php?s=aa6f015109fd7e4c7e30d2fd8b717497&t=141670&page=3
127  */
128 /* ---------------------------------------------------------------------------
129  Name : replace - Search & replace a substring by another one.
130  Creation : Thierry Husson, Sept 2010
131  Parameters :
132  str : Big string where we search
133  oldstr : Substring we are looking for
134  newstr : Substring we want to replace with
135  count : Optional pointer to int (input / output value). NULL to ignore.
136  Input: Maximum replacements to be done. NULL or < 1 to do all.
137  Output: Number of replacements done or -1 if not enough memory.
138  Returns : Pointer to the new string or NULL if error.
139  Notes :
140  - Case sensitive - Otherwise, replace functions "strstr" by "strcasestr"
141  - Always allocates memory for the result.
142 --------------------------------------------------------------------------- */
143 static char*
145  const char *str,
146  const char *oldstr, const char *newstr,
147  int *count
148 ) {
149  const char *tmp = str;
150  char *result;
151  int found = 0;
152  int length, reslen;
153  int oldlen = strlen(oldstr);
154  int newlen = strlen(newstr);
155  int limit = (count != NULL && *count > 0) ? *count : -1;
156 
157  tmp = str;
158  while ((tmp = strstr(tmp, oldstr)) != NULL && found != limit)
159  found++, tmp += oldlen;
160 
161  length = strlen(str) + found * (newlen - oldlen);
162  if ((result = (char *) rtalloc(length + 1)) == NULL) {
163  rterror(_("strreplace: Not enough memory"));
164  found = -1;
165  }
166  else {
167  tmp = str;
168  limit = found; /* Countdown */
169  reslen = 0; /* length of current result */
170 
171  /* Replace each old string found with new string */
172  while ((limit-- > 0) && (tmp = strstr(tmp, oldstr)) != NULL) {
173  length = (tmp - str); /* Number of chars to keep intouched */
174  strncpy(result + reslen, str, length); /* Original part keeped */
175  strcpy(result + (reslen += length), newstr); /* Insert new string */
176 
177  reslen += newlen;
178  tmp += oldlen;
179  str = tmp;
180  }
181  strcpy(result + reslen, str); /* Copies last part and ending null char */
182  }
183 
184  if (count != NULL) *count = found;
185  return result;
186 }
187 
188 static char *
189 strtolower(char * str) {
190  int j;
191 
192  for (j = strlen(str) - 1; j >= 0; j--)
193  str[j] = tolower(str[j]);
194 
195  return str;
196 }
197 
198 /* split a string based on a delimiter */
199 static char**
200 strsplit(const char *str, const char *delimiter, uint32_t *n) {
201  char *tmp = NULL;
202  char **rtn = NULL;
203  char *token = NULL;
204 
205  *n = 0;
206  if (!str)
207  return NULL;
208 
209  /* copy str to tmp as strtok will mangle the string */
210  tmp = rtalloc(sizeof(char) * (strlen(str) + 1));
211  if (NULL == tmp) {
212  rterror(_("strsplit: Not enough memory"));
213  return NULL;
214  }
215  strcpy(tmp, str);
216 
217  if (!strlen(tmp) || !delimiter || !strlen(delimiter)) {
218  *n = 1;
219  rtn = (char **) rtalloc(*n * sizeof(char *));
220  if (NULL == rtn) {
221  rterror(_("strsplit: Not enough memory"));
222  return NULL;
223  }
224  rtn[0] = (char *) rtalloc(sizeof(char) * (strlen(tmp) + 1));
225  if (NULL == rtn[0]) {
226  rterror(_("strsplit: Not enough memory"));
227  return NULL;
228  }
229  strcpy(rtn[0], tmp);
230  rtdealloc(tmp);
231  return rtn;
232  }
233 
234  token = strtok(tmp, delimiter);
235  while (token != NULL) {
236  if (*n < 1) {
237  rtn = (char **) rtalloc(sizeof(char *));
238  }
239  else {
240  rtn = (char **) rtrealloc(rtn, (*n + 1) * sizeof(char *));
241  }
242  if (NULL == rtn) {
243  rterror(_("strsplit: Not enough memory"));
244  return NULL;
245  }
246 
247  rtn[*n] = NULL;
248  rtn[*n] = (char *) rtalloc(sizeof(char) * (strlen(token) + 1));
249  if (NULL == rtn[*n]) {
250  rterror(_("strsplit: Not enough memory"));
251  return NULL;
252  }
253 
254  strcpy(rtn[*n], token);
255  *n = *n + 1;
256 
257  token = strtok(NULL, delimiter);
258  }
259 
260  rtdealloc(tmp);
261  return rtn;
262 }
263 
264 static char*
265 trim(const char *input) {
266  char *rtn;
267  char *ptr;
268  uint32_t offset = 0;
269  size_t len = 0;
270 
271  if (!input)
272  return NULL;
273  else if (!*input)
274  return (char *) input;
275 
276  /* trim left */
277  while (isspace(*input))
278  input++;
279 
280  /* trim right */
281  ptr = ((char *) input) + strlen(input);
282  while (isspace(*--ptr))
283  offset++;
284 
285  len = strlen(input) - offset + 1;
286  rtn = rtalloc(sizeof(char) * len);
287  if (NULL == rtn) {
288  rterror(_("trim: Not enough memory"));
289  return NULL;
290  }
291  strncpy(rtn, input, len);
292 
293  return rtn;
294 }
295 
296 static char*
297 chartrim(const char *input, char *remove) {
298  char *rtn = NULL;
299  char *ptr = NULL;
300  uint32_t offset = 0;
301  size_t len = 0;
302 
303  if (!input)
304  return NULL;
305  else if (!*input)
306  return (char *) input;
307 
308  /* trim left */
309  while (strchr(remove, *input) != NULL)
310  input++;
311 
312  /* trim right */
313  ptr = ((char *) input) + strlen(input);
314  while (strchr(remove, *--ptr) != NULL)
315  offset++;
316 
317  len = strlen(input) - offset + 1;
318  rtn = rtalloc(sizeof(char) * len);
319  if (NULL == rtn) {
320  rterror(_("chartrim: Not enough memory"));
321  return NULL;
322  }
323  strncpy(rtn, input, len);
324  rtn[strlen(input) - offset] = '\0';
325 
326  return rtn;
327 }
328 
329 static void
330 usage() {
331  printf(_("RELEASE: %s GDAL_VERSION=%d (%s)\n"), POSTGIS_LIB_VERSION, POSTGIS_GDAL_VERSION, xstr(POSTGIS_REVISION));
332  printf(_(
333  "USAGE: raster2pgsql [<options>] <raster>[ <raster>[ ...]] [[<schema>.]<table>]\n"
334  " Multiple rasters can also be specified using wildcards (*,?).\n"
335  "\n"
336  "OPTIONS:\n"
337  ));
338  /*
339  printf(_(
340  " -s [<from>:]<srid> Set the SRID field. Defaults to %d.\n"
341  " Optionally reprojects from given SRID (cannot be used with -Y).\n"
342  " Raster's metadata will be checked to determine an appropriate SRID.\n"
343  " If a srid of %d is provided (either as from or as target).\n"
344  ), SRID_UNKNOWN, SRID_UNKNOWN);
345  */
346  printf(_(
347  " -s <srid> Set the SRID field. Defaults to %d. If SRID not\n"
348  " provided or is %d, raster's metadata will be checked to\n"
349  " determine an appropriate SRID.\n"
351  printf(_(
352  " -b <band> Index (1-based) of band to extract from raster. For more\n"
353  " than one band index, separate with comma (,). Ranges can be\n"
354  " defined by separating with dash (-). If unspecified, all bands\n"
355  " of raster will be extracted.\n"
356  ));
357  printf(_(
358  " -t <tile size> Cut raster into tiles to be inserted one per\n"
359  " table row. <tile size> is expressed as WIDTHxHEIGHT.\n"
360  " <tile size> can also be \"auto\" to allow the loader to compute\n"
361  " an appropriate tile size using the first raster and applied to\n"
362  " all rasters.\n"
363  ));
364  printf(_(
365  " -P Pad right-most and bottom-most tiles to guarantee that all tiles\n"
366  " have the same width and height.\n"
367  ));
368  printf(_(
369  " -R Register the raster as an out-of-db (filesystem) raster. Provided\n"
370  " raster should have absolute path to the file\n"
371  ));
372  printf(_(
373  " (-d|a|c|p) These are mutually exclusive options:\n"
374  " -d Drops the table, then recreates it and populates\n"
375  " it with current raster data.\n"
376  " -a Appends raster into current table, must be\n"
377  " exactly the same table schema.\n"
378  " -c Creates a new table and populates it, this is the\n"
379  " default if you do not specify any options.\n"
380  " -p Prepare mode, only creates the table.\n"
381  ));
382  printf(_(
383  " -f <column> Specify the name of the raster column\n"
384  ));
385  printf(_(
386  " -F Add a column with the filename of the raster.\n"
387  ));
388  printf(_(
389  " -n <column> Specify the name of the filename column. Implies -F.\n"
390  ));
391  printf(_(
392  " -l <overview factor> Create overview of the raster. For more than\n"
393  " one factor, separate with comma(,). Overview table name follows\n"
394  " the pattern o_<overview factor>_<table>. Created overview is\n"
395  " stored in the database and is not affected by -R.\n"
396  ));
397  printf(_(
398  " -q Wrap PostgreSQL identifiers in quotes.\n"
399  ));
400  printf(_(
401  " -I Create a GIST spatial index on the raster column. The ANALYZE\n"
402  " command will automatically be issued for the created index.\n"
403  ));
404  printf(_(
405  " -M Run VACUUM ANALYZE on the table of the raster column. Most\n"
406  " useful when appending raster to existing table with -a.\n"
407  ));
408  printf(_(
409  " -C Set the standard set of constraints on the raster\n"
410  " column after the rasters are loaded. Some constraints may fail\n"
411  " if one or more rasters violate the constraint.\n"
412  " -x Disable setting the max extent constraint. Only applied if\n"
413  " -C flag is also used.\n"
414  " -r Set the constraints (spatially unique and coverage tile) for\n"
415  " regular blocking. Only applied if -C flag is also used.\n"
416  ));
417  printf(_(
418  " -T <tablespace> Specify the tablespace for the new table.\n"
419  " Note that indices (including the primary key) will still use\n"
420  " the default tablespace unless the -X flag is also used.\n"
421  ));
422  printf(_(
423  " -X <tablespace> Specify the tablespace for the table's new index.\n"
424  " This applies to the primary key and the spatial index if\n"
425  " the -I flag is used.\n"
426  ));
427  printf(_(
428  " -N <nodata> NODATA value to use on bands without a NODATA value.\n"
429  ));
430  printf(_(
431  " -k Skip NODATA value checks for each raster band.\n"
432  ));
433  printf(_(
434  " -E <endian> Control endianness of generated binary output of\n"
435  " raster. Use 0 for XDR and 1 for NDR (default). Only NDR\n"
436  " is supported at this time.\n"
437  ));
438  printf(_(
439  " -V <version> Specify version of output WKB format. Default\n"
440  " is 0. Only 0 is supported at this time.\n"
441  ));
442  printf(_(
443  " -e Execute each statement individually, do not use a transaction.\n"
444  ));
445  printf(_(
446  " -Y Use COPY statements instead of INSERT statements.\n"
447  ));
448  printf(_(
449  " -G Print the supported GDAL raster formats.\n"
450  ));
451  printf(_(
452  " -? Display this help screen.\n"
453  ));
454 }
455 
456 static void
457 calc_tile_size(uint32_t dimX, uint32_t dimY, int *tileX, int *tileY)
458 {
459  uint32_t min_tile_size = 30;
460  uint32_t max_tile_size = 300;
461 
462  for (uint8_t current_dimension = 0; current_dimension <= 1; current_dimension++)
463  {
464  uint32_t img_size = (current_dimension == 0) ? dimX : dimY;
465  uint32_t best_gap = max_tile_size;
466  uint32_t best_size = img_size;
467 
468  if (img_size > max_tile_size)
469  {
470  for (uint32_t tile_size = max_tile_size; tile_size >= min_tile_size; tile_size--)
471  {
472  uint32_t gap = img_size % tile_size;
473  if (gap < best_gap)
474  {
475  best_gap = gap;
476  best_size = tile_size;
477  }
478  }
479  }
480 
481  if (current_dimension == 0)
482  *tileX = best_size;
483  else
484  *tileY = best_size;
485  }
486 }
487 
488 static void
489 init_rastinfo(RASTERINFO *info) {
490  info->srid = SRID_UNKNOWN;
491  info->srs = NULL;
492  memset(info->dim, 0, sizeof(uint32_t) * 2);
493  info->nband_count = 0;
494  info->nband = NULL;
495  info->gdalbandtype = NULL;
496  info->bandtype = NULL;
497  info->hasnodata = NULL;
498  info->nodataval = NULL;
499  memset(info->gt, 0, sizeof(double) * 6);
500  memset(info->tile_size, 0, sizeof(int) * 2);
501 }
502 
503 static void
504 rtdealloc_rastinfo(RASTERINFO *info) {
505  if (info->srs != NULL)
506  rtdealloc(info->srs);
507  if (info->nband_count > 0 && info->nband != NULL)
508  rtdealloc(info->nband);
509  if (info->gdalbandtype != NULL)
510  rtdealloc(info->gdalbandtype);
511  if (info->bandtype != NULL)
512  rtdealloc(info->bandtype);
513  if (info->hasnodata != NULL)
514  rtdealloc(info->hasnodata);
515  if (info->nodataval != NULL)
516  rtdealloc(info->nodataval);
517 }
518 
519 static int
520 copy_rastinfo(RASTERINFO *dst, RASTERINFO *src) {
521  if (src->srs != NULL) {
522  dst->srs = rtalloc(sizeof(char) * (strlen(src->srs) + 1));
523  if (dst->srs == NULL) {
524  rterror(_("copy_rastinfo: Not enough memory"));
525  return 0;
526  }
527  strcpy(dst->srs, src->srs);
528  }
529  memcpy(dst->dim, src->dim, sizeof(uint32_t) * 2);
530  dst->nband_count = src->nband_count;
531  if (src->nband_count && src->nband != NULL) {
532  dst->nband = rtalloc(sizeof(int) * src->nband_count);
533  if (dst->nband == NULL) {
534  rterror(_("copy_rastinfo: Not enough memory"));
535  return 0;
536  }
537  memcpy(dst->nband, src->nband, sizeof(int) * src->nband_count);
538  }
539  if (src->gdalbandtype != NULL) {
540  dst->gdalbandtype = rtalloc(sizeof(GDALDataType) * src->nband_count);
541  if (dst->gdalbandtype == NULL) {
542  rterror(_("copy_rastinfo: Not enough memory"));
543  return 0;
544  }
545  memcpy(dst->gdalbandtype, src->gdalbandtype, sizeof(GDALDataType) * src->nband_count);
546  }
547  if (src->bandtype != NULL) {
548  dst->bandtype = rtalloc(sizeof(rt_pixtype) * src->nband_count);
549  if (dst->bandtype == NULL) {
550  rterror(_("copy_rastinfo: Not enough memory"));
551  return 0;
552  }
553  memcpy(dst->bandtype, src->bandtype, sizeof(rt_pixtype) * src->nband_count);
554  }
555  if (src->hasnodata != NULL) {
556  dst->hasnodata = rtalloc(sizeof(int) * src->nband_count);
557  if (dst->hasnodata == NULL) {
558  rterror(_("copy_rastinfo: Not enough memory"));
559  return 0;
560  }
561  memcpy(dst->hasnodata, src->hasnodata, sizeof(int) * src->nband_count);
562  }
563  if (src->nodataval != NULL) {
564  dst->nodataval = rtalloc(sizeof(double) * src->nband_count);
565  if (dst->nodataval == NULL) {
566  rterror(_("copy_rastinfo: Not enough memory"));
567  return 0;
568  }
569  memcpy(dst->nodataval, src->nodataval, sizeof(double) * src->nband_count);
570  }
571  memcpy(dst->gt, src->gt, sizeof(double) * 6);
572  memcpy(dst->tile_size, src->tile_size, sizeof(int) * 2);
573 
574  return 1;
575 }
576 
577 static void
578 diff_rastinfo(RASTERINFO *x, RASTERINFO *ref) {
579  static uint8_t msg[6] = {0};
580  uint32_t i = 0;
581 
582  /* # of bands */
583  if (
584  !msg[0] &&
585  x->nband_count != ref->nband_count
586  ) {
587  rtwarn(_("Different number of bands found in the set of rasters being converted to PostGIS raster"));
588  msg[0]++;
589  }
590 
591  /* pixel types */
592  if (!msg[1]) {
593  for (i = 0; i < ref->nband_count; i++) {
594  if (x->bandtype[i] != ref->bandtype[i]) {
595  rtwarn(_("Different pixel types found for band %d in the set of rasters being converted to PostGIS raster"), ref->nband[i]);
596  msg[1]++;
597  }
598  }
599  }
600 
601  /* hasnodata */
602  if (!msg[2]) {
603  for (i = 0; i < ref->nband_count; i++) {
604  if (x->hasnodata[i] != ref->hasnodata[i]) {
605  rtwarn(_("Different hasnodata flags found for band %d in the set of rasters being converted to PostGIS raster"), ref->nband[i]);
606  msg[2]++;
607  }
608  }
609  }
610 
611  /* nodataval */
612  if (!msg[3]) {
613  for (i = 0; i < ref->nband_count; i++) {
614  if (!x->hasnodata[i] && !ref->hasnodata[i]) continue;
615  if (x->hasnodata[i] != ref->hasnodata[i]) {
616  rtwarn(_("Different NODATA values found for band %d in the set of rasters being converted to PostGIS raster"), ref->nband[i]);
617  msg[3]++;
618  }
619  }
620  }
621 
622  /* alignment */
623  if (!msg[4]) {
624  rt_raster rx = NULL;
625  rt_raster rref = NULL;
626  int err;
627  int aligned;
628 
629  if (
630  (rx = rt_raster_new(1, 1)) == NULL ||
631  (rref = rt_raster_new(1, 1)) == NULL
632  ) {
633  rterror(_("diff_rastinfo: Could not allocate memory for raster alignment test"));
634  if (rx != NULL) rt_raster_destroy(rx);
635  if (rref != NULL) rt_raster_destroy(rref);
636  return;
637  }
638 
641 
642  err = rt_raster_same_alignment(rx, rref, &aligned, NULL);
643  rt_raster_destroy(rx);
644  rt_raster_destroy(rref);
645  if (err != ES_NONE) {
646  rterror(_("diff_rastinfo: Could not run raster alignment test"));
647  return;
648  }
649 
650  if (!aligned) {
651  rtwarn(_("Raster with different alignment found in the set of rasters being converted to PostGIS raster"));
652  msg[4]++;
653  }
654  }
655 
656  /* tile size */
657  if (!msg[5]) {
658  for (i = 0; i < 2; i++) {
659  if (x->tile_size[i] != ref->tile_size[i]) {
660  rtwarn(_("Different tile sizes found in the set of rasters being converted to PostGIS raster"));
661  msg[5]++;
662  break;
663  }
664  }
665  }
666 }
667 
668 static void
669 init_config(RTLOADERCFG *config) {
670  config->rt_file_count = 0;
671  config->rt_file = NULL;
672  config->rt_filename = NULL;
673  config->schema = NULL;
674  config->table = NULL;
675  config->raster_column = NULL;
676  config->file_column = 0;
677  config->file_column_name = NULL;
678  config->overview_count = 0;
679  config->overview = NULL;
680  config->overview_table = NULL;
681  config->quoteident = 0;
682  config->srid = config->out_srid = SRID_UNKNOWN;
683  config->nband = NULL;
684  config->nband_count = 0;
685  memset(config->tile_size, 0, sizeof(int) * 2);
686  config->pad_tile = 0;
687  config->outdb = 0;
688  config->opt = 'c';
689  config->idx = 0;
690  config->maintenance = 0;
691  config->constraints = 0;
692  config->max_extent = 1;
693  config->regular_blocking = 0;
694  config->tablespace = NULL;
695  config->idx_tablespace = NULL;
696  config->hasnodata = 0;
697  config->nodataval = 0;
698  config->skip_nodataval_check = 0;
699  config->endian = 1;
700  config->version = 0;
701  config->transaction = 1;
702  config->copy_statements = 0;
703 }
704 
705 static void
706 rtdealloc_config(RTLOADERCFG *config) {
707  int i = 0;
708  if (config->rt_file_count) {
709  for (i = config->rt_file_count - 1; i >= 0; i--) {
710  rtdealloc(config->rt_file[i]);
711  if (config->rt_filename)
712  rtdealloc(config->rt_filename[i]);
713  }
714  rtdealloc(config->rt_file);
715  if (config->rt_filename)
716  rtdealloc(config->rt_filename);
717  }
718  if (config->schema != NULL)
719  rtdealloc(config->schema);
720  if (config->table != NULL)
721  rtdealloc(config->table);
722  if (config->raster_column != NULL)
723  rtdealloc(config->raster_column);
724  if (config->file_column_name != NULL)
725  rtdealloc(config->file_column_name);
726  if (config->overview_count > 0) {
727  if (config->overview != NULL)
728  rtdealloc(config->overview);
729  if (config->overview_table != NULL) {
730  for (i = config->overview_count - 1; i >= 0; i--)
731  rtdealloc(config->overview_table[i]);
732  rtdealloc(config->overview_table);
733  }
734  }
735  if (config->nband_count > 0 && config->nband != NULL)
736  rtdealloc(config->nband);
737  if (config->tablespace != NULL)
738  rtdealloc(config->tablespace);
739  if (config->idx_tablespace != NULL)
740  rtdealloc(config->idx_tablespace);
741 
742  rtdealloc(config);
743 }
744 
745 static void
746 init_stringbuffer(STRINGBUFFER *buffer) {
747  buffer->line = NULL;
748  buffer->length = 0;
749 }
750 
751 static void
752 rtdealloc_stringbuffer(STRINGBUFFER *buffer, int freebuffer) {
753  if (buffer->length) {
754  uint32_t i = 0;
755  for (i = 0; i < buffer->length; i++) {
756  if (buffer->line[i] != NULL)
757  rtdealloc(buffer->line[i]);
758  }
759  rtdealloc(buffer->line);
760  }
761  buffer->line = NULL;
762  buffer->length = 0;
763 
764  if (freebuffer)
765  rtdealloc(buffer);
766 }
767 
768 static void
769 dump_stringbuffer(STRINGBUFFER *buffer) {
770  uint32_t i = 0;
771 
772  for (i = 0; i < buffer->length; i++) {
773  printf("%s\n", buffer->line[i]);
774  }
775 }
776 
777 static void
778 flush_stringbuffer(STRINGBUFFER *buffer) {
779  dump_stringbuffer(buffer);
780  rtdealloc_stringbuffer(buffer, 0);
781 }
782 
783 /* Takes ownership of the passed string */
784 static int
785 append_stringbuffer(STRINGBUFFER *buffer, const char *str) {
786  buffer->length++;
787 
788  buffer->line = rtrealloc(buffer->line, sizeof(char *) * buffer->length);
789  if (buffer->line == NULL) {
790  rterror(_("append_stringbuffer: Could not allocate memory for appending string to buffer"));
791  return 0;
792  }
793 
794  buffer->line[buffer->length - 1] = (char *) str;
795 
796  return 1;
797 }
798 
799 static int
800 append_sql_to_buffer(STRINGBUFFER *buffer, const char *str) {
801  if (buffer->length > 9)
802  flush_stringbuffer(buffer);
803 
804  return append_stringbuffer(buffer, str);
805 }
806 
807 static int
808 copy_from(const char *schema, const char *table, const char *column,
809  const char *filename, const char *file_column_name,
811 {
812  char *sql = NULL;
813  uint32_t len = 0;
814 
815  assert(table != NULL);
816  assert(column != NULL);
817 
818  len = strlen("COPY () FROM stdin;") + 1;
819  if (schema != NULL)
820  len += strlen(schema);
821  len += strlen(table);
822  len += strlen(column);
823  if (filename != NULL)
824  len += strlen(",") + strlen(file_column_name);
825 
826  sql = rtalloc(sizeof(char) * len);
827  if (sql == NULL) {
828  rterror(_("copy_from: Could not allocate memory for COPY statement"));
829  return 0;
830  }
831  sprintf(sql, "COPY %s%s (%s%s%s) FROM stdin;",
832  (schema != NULL ? schema : ""),
833  table,
834  column,
835  (filename != NULL ? "," : ""),
836  (filename != NULL ? file_column_name : "")
837  );
838 
839  append_sql_to_buffer(buffer, sql);
840  sql = NULL;
841 
842  return 1;
843 }
844 
845 static int
846 copy_from_end(STRINGBUFFER *buffer)
847 {
848  /* end of data */
849  append_sql_to_buffer(buffer, strdup("\\."));
850 
851  return 1;
852 }
853 
854 static int
855 insert_records(
856  const char *schema, const char *table, const char *column,
857  const char *filename, const char *file_column_name,
858  int copy_statements, int out_srid,
859  STRINGBUFFER *tileset, STRINGBUFFER *buffer
860 ) {
861  char *fn = NULL;
862  uint32_t len = 0;
863  char *sql = NULL;
864  uint32_t x = 0;
865 
866  assert(table != NULL);
867  assert(column != NULL);
868 
869  /* COPY statements */
870  if (copy_statements) {
871 
872  if (!copy_from(
873  schema, table, column,
874  (file_column_name ? filename : NULL), file_column_name,
875  buffer
876  )) {
877  rterror(_("insert_records: Could not add COPY statement to string buffer"));
878  return 0;
879  }
880 
881 
882  /* escape tabs in filename */
883  if (filename != NULL)
884  fn = strreplace(filename, "\t", "\\t", NULL);
885 
886  /* rows */
887  for (x = 0; x < tileset->length; x++) {
888  len = strlen(tileset->line[x]) + 1;
889 
890  if (filename != NULL)
891  len += strlen(fn) + 1;
892 
893  sql = rtalloc(sizeof(char) * len);
894  if (sql == NULL) {
895  rterror(_("insert_records: Could not allocate memory for COPY statement"));
896  return 0;
897  }
898  sprintf(sql, "%s%s%s",
899  tileset->line[x],
900  (filename != NULL ? "\t" : ""),
901  (filename != NULL ? fn : "")
902  );
903 
904  append_sql_to_buffer(buffer, sql);
905  sql = NULL;
906  }
907 
908  if (!copy_from_end(buffer)) {
909  rterror(_("process_rasters: Could not add COPY end statement to string buffer"));
910  return 0;
911  }
912 
913  }
914  /* INSERT statements */
915  else {
916  len = strlen("INSERT INTO () VALUES (ST_Transform(''::raster,xxxxxxxxx));") + 1;
917  if (schema != NULL)
918  len += strlen(schema);
919  len += strlen(table);
920  len += strlen(column);
921  if (filename != NULL)
922  len += strlen(",") + strlen(file_column_name);
923 
924  /* escape single-quotes in filename */
925  if (filename != NULL)
926  fn = strreplace(filename, "'", "''", NULL);
927 
928  for (x = 0; x < tileset->length; x++) {
929  char *ptr;
930  int sqllen = len;
931 
932  sqllen += strlen(tileset->line[x]);
933  if (filename != NULL)
934  sqllen += strlen(",''") + strlen(fn);
935 
936  sql = rtalloc(sizeof(char) * sqllen);
937  if (sql == NULL) {
938  rterror(_("insert_records: Could not allocate memory for INSERT statement"));
939  return 0;
940  }
941  ptr = sql;
942  ptr += sprintf(sql, "INSERT INTO %s%s (%s%s%s) VALUES (",
943  (schema != NULL ? schema : ""),
944  table,
945  column,
946  (filename != NULL ? "," : ""),
947  (filename != NULL ? file_column_name : "")
948  );
949  if (out_srid != SRID_UNKNOWN) {
950  ptr += sprintf(ptr, "ST_Transform(");
951  }
952  ptr += sprintf(ptr, "'%s'::raster",
953  tileset->line[x]
954  );
955  if (out_srid != SRID_UNKNOWN) {
956  ptr += sprintf(ptr, ", %d)", out_srid);
957  }
958  if (filename != NULL) {
959  ptr += sprintf(ptr, ",'%s'", fn);
960  }
961  ptr += sprintf(ptr, ");");
962 
963  append_sql_to_buffer(buffer, sql);
964  sql = NULL;
965  }
966  }
967 
968  if (fn != NULL) rtdealloc(fn);
969  return 1;
970 }
971 
972 static int
973 drop_table(const char *schema, const char *table, STRINGBUFFER *buffer) {
974  char *sql = NULL;
975  uint32_t len = 0;
976 
977  len = strlen("DROP TABLE IF EXISTS ;") + 1;
978  if (schema != NULL)
979  len += strlen(schema);
980  len += strlen(table);
981 
982  sql = rtalloc(sizeof(char) * len);
983  if (sql == NULL) {
984  rterror(_("drop_table: Could not allocate memory for DROP TABLE statement"));
985  return 0;
986  }
987  sprintf(sql, "DROP TABLE IF EXISTS %s%s;",
988  (schema != NULL ? schema : ""),
989  table
990  );
991 
992  append_sql_to_buffer(buffer, sql);
993 
994  return 1;
995 }
996 
997 static int
998 create_table(
999  const char *schema, const char *table, const char *column,
1000  const int file_column, const char *file_column_name,
1001  const char *tablespace, const char *idx_tablespace,
1003 ) {
1004  char *sql = NULL;
1005  uint32_t len = 0;
1006 
1007  assert(table != NULL);
1008  assert(column != NULL);
1009 
1010  len = strlen("CREATE TABLE (\"rid\" serial PRIMARY KEY, raster);") + 1;
1011  if (schema != NULL)
1012  len += strlen(schema);
1013  len += strlen(table);
1014  len += strlen(column);
1015  if (file_column)
1016  len += strlen(", text") + strlen(file_column_name);
1017  if (tablespace != NULL)
1018  len += strlen(" TABLESPACE ") + strlen(tablespace);
1019  if (idx_tablespace != NULL)
1020  len += strlen(" USING INDEX TABLESPACE ") + strlen(idx_tablespace);
1021 
1022  sql = rtalloc(sizeof(char) * len);
1023  if (sql == NULL) {
1024  rterror(_("create_table: Could not allocate memory for CREATE TABLE statement"));
1025  return 0;
1026  }
1027  sprintf(sql, "CREATE TABLE %s%s (\"rid\" serial PRIMARY KEY%s%s,%s raster%s%s%s)%s%s;",
1028  (schema != NULL ? schema : ""),
1029  table,
1030  (idx_tablespace != NULL ? " USING INDEX TABLESPACE " : ""),
1031  (idx_tablespace != NULL ? idx_tablespace : ""),
1032  column,
1033  (file_column ? "," : ""),
1034  (file_column ? file_column_name : ""),
1035  (file_column ? " text" : ""),
1036  (tablespace != NULL ? " TABLESPACE " : ""),
1037  (tablespace != NULL ? tablespace : "")
1038  );
1039 
1040  append_sql_to_buffer(buffer, sql);
1041 
1042  return 1;
1043 }
1044 
1045 static int
1046 create_index(
1047  const char *schema, const char *table, const char *column,
1048  const char *tablespace,
1050 ) {
1051  char *sql = NULL;
1052  uint32_t len = 0;
1053  char *_table = NULL;
1054  char *_column = NULL;
1055 
1056  assert(table != NULL);
1057  assert(column != NULL);
1058 
1059  _table = chartrim(table, "\"");
1060  _column = chartrim(column, "\"");
1061 
1062  /* create index */
1063  len = strlen("CREATE INDEX \"__gist\" ON USING gist (st_convexhull());") + 1;
1064  if (schema != NULL)
1065  len += strlen(schema);
1066  len += strlen(_table);
1067  len += strlen(_column);
1068  len += strlen(table);
1069  len += strlen(column);
1070  if (tablespace != NULL)
1071  len += strlen(" TABLESPACE ") + strlen(tablespace);
1072 
1073  sql = rtalloc(sizeof(char) * len);
1074  if (sql == NULL) {
1075  rterror(_("create_index: Could not allocate memory for CREATE INDEX statement"));
1076  rtdealloc(_table);
1077  rtdealloc(_column);
1078  return 0;
1079  }
1080  sprintf(sql, "CREATE INDEX ON %s%s USING gist (st_convexhull(%s))%s%s;",
1081  (schema != NULL ? schema : ""),
1082  table,
1083  column,
1084  (tablespace != NULL ? " TABLESPACE " : ""),
1085  (tablespace != NULL ? tablespace : "")
1086  );
1087  rtdealloc(_table);
1088  rtdealloc(_column);
1089 
1090  append_sql_to_buffer(buffer, sql);
1091 
1092  return 1;
1093 }
1094 
1095 static int
1096 analyze_table(
1097  const char *schema, const char *table,
1099 ) {
1100  char *sql = NULL;
1101  uint32_t len = 0;
1102 
1103  assert(table != NULL);
1104 
1105  len = strlen("ANALYZE ;") + 1;
1106  if (schema != NULL)
1107  len += strlen(schema);
1108  len += strlen(table);
1109 
1110  sql = rtalloc(sizeof(char) * len);
1111  if (sql == NULL) {
1112  rterror(_("analyze_table: Could not allocate memory for ANALYZE TABLE statement"));
1113  return 0;
1114  }
1115  sprintf(sql, "ANALYZE %s%s;",
1116  (schema != NULL ? schema : ""),
1117  table
1118  );
1119 
1120  append_sql_to_buffer(buffer, sql);
1121 
1122  return 1;
1123 }
1124 
1125 static int
1126 vacuum_table(
1127  const char *schema, const char *table,
1129 ) {
1130  char *sql = NULL;
1131  uint32_t len = 0;
1132 
1133  assert(table != NULL);
1134 
1135  len = strlen("VACUUM ANALYZE ;") + 1;
1136  if (schema != NULL)
1137  len += strlen(schema);
1138  len += strlen(table);
1139 
1140  sql = rtalloc(sizeof(char) * len);
1141  if (sql == NULL) {
1142  rterror(_("vacuum_table: Could not allocate memory for VACUUM statement"));
1143  return 0;
1144  }
1145  sprintf(sql, "VACUUM ANALYZE %s%s;",
1146  (schema != NULL ? schema : ""),
1147  table
1148  );
1149 
1150  append_sql_to_buffer(buffer, sql);
1151 
1152  return 1;
1153 }
1154 
1155 static int
1156 add_raster_constraints(
1157  const char *schema, const char *table, const char *column,
1158  int regular_blocking, int max_extent,
1160 ) {
1161  char *sql = NULL;
1162  uint32_t len = 0;
1163 
1164  char *_tmp = NULL;
1165  char *_schema = NULL;
1166  char *_table = NULL;
1167  char *_column = NULL;
1168 
1169  assert(table != NULL);
1170  assert(column != NULL);
1171 
1172  /* schema */
1173  if (schema != NULL) {
1174  _tmp = chartrim(schema, ".");
1175  _schema = chartrim(_tmp, "\"");
1176  rtdealloc(_tmp);
1177  _tmp = strreplace(_schema, "'", "''", NULL);
1178  rtdealloc(_schema);
1179  _schema = _tmp;
1180  }
1181 
1182  /* table */
1183  _tmp = chartrim(table, "\"");
1184  _table = strreplace(_tmp, "'", "''", NULL);
1185  rtdealloc(_tmp);
1186 
1187  /* column */
1188  _tmp = chartrim(column, "\"");
1189  _column = strreplace(_tmp, "'", "''", NULL);
1190  rtdealloc(_tmp);
1191 
1192  len = strlen("SELECT AddRasterConstraints('','','',TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE,TRUE,TRUE,FALSE);") + 1;
1193  if (_schema != NULL)
1194  len += strlen(_schema);
1195  len += strlen(_table);
1196  len += strlen(_column);
1197 
1198  sql = rtalloc(sizeof(char) * len);
1199  if (sql == NULL) {
1200  rterror(_("add_raster_constraints: Could not allocate memory for AddRasterConstraints statement"));
1201  return 0;
1202  }
1203  sprintf(sql, "SELECT AddRasterConstraints('%s','%s','%s',TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,%s,TRUE,TRUE,TRUE,TRUE,%s);",
1204  (_schema != NULL ? _schema : ""),
1205  _table,
1206  _column,
1207  (regular_blocking ? "TRUE" : "FALSE"),
1208  (max_extent ? "TRUE" : "FALSE")
1209  );
1210 
1211  if (_schema != NULL)
1212  rtdealloc(_schema);
1213  rtdealloc(_table);
1214  rtdealloc(_column);
1215 
1216  append_sql_to_buffer(buffer, sql);
1217 
1218  return 1;
1219 }
1220 
1221 static int
1222 add_overview_constraints(
1223  const char *ovschema, const char *ovtable, const char *ovcolumn,
1224  const char *schema, const char *table, const char *column,
1225  const int factor,
1227 ) {
1228  char *sql = NULL;
1229  uint32_t len = 0;
1230 
1231  char *_tmp = NULL;
1232 
1233  char *_ovschema = NULL;
1234  char *_ovtable = NULL;
1235  char *_ovcolumn = NULL;
1236 
1237  char *_schema = NULL;
1238  char *_table = NULL;
1239  char *_column = NULL;
1240 
1241  assert(ovtable != NULL);
1242  assert(ovcolumn != NULL);
1243  assert(table != NULL);
1244  assert(column != NULL);
1245  assert(factor >= MINOVFACTOR && factor <= MAXOVFACTOR);
1246 
1247  /* overview schema */
1248  if (ovschema != NULL) {
1249  _tmp = chartrim(ovschema, ".");
1250  _ovschema = chartrim(_tmp, "\"");
1251  rtdealloc(_tmp);
1252  _tmp = strreplace(_ovschema, "'", "''", NULL);
1253  rtdealloc(_ovschema);
1254  _ovschema = _tmp;
1255  }
1256 
1257  /* overview table */
1258  _tmp = chartrim(ovtable, "\"");
1259  _ovtable = strreplace(_tmp, "'", "''", NULL);
1260  rtdealloc(_tmp);
1261 
1262  /* overview column*/
1263  _tmp = chartrim(ovcolumn, "\"");
1264  _ovcolumn = strreplace(_tmp, "'", "''", NULL);
1265  rtdealloc(_tmp);
1266 
1267  /* schema */
1268  if (schema != NULL) {
1269  _tmp = chartrim(schema, ".");
1270  _schema = chartrim(_tmp, "\"");
1271  rtdealloc(_tmp);
1272  _tmp = strreplace(_schema, "'", "''", NULL);
1273  rtdealloc(_schema);
1274  _schema = _tmp;
1275  }
1276 
1277  /* table */
1278  _tmp = chartrim(table, "\"");
1279  _table = strreplace(_tmp, "'", "''", NULL);
1280  rtdealloc(_tmp);
1281 
1282  /* column */
1283  _tmp = chartrim(column, "\"");
1284  _column = strreplace(_tmp, "'", "''", NULL);
1285  rtdealloc(_tmp);
1286 
1287  len = strlen("SELECT AddOverviewConstraints('','','','','','',);") + 5;
1288  if (_ovschema != NULL)
1289  len += strlen(_ovschema);
1290  len += strlen(_ovtable);
1291  len += strlen(_ovcolumn);
1292  if (_schema != NULL)
1293  len += strlen(_schema);
1294  len += strlen(_table);
1295  len += strlen(_column);
1296 
1297  sql = rtalloc(sizeof(char) * len);
1298  if (sql == NULL) {
1299  rterror(_("add_overview_constraints: Could not allocate memory for AddOverviewConstraints statement"));
1300  return 0;
1301  }
1302  sprintf(sql, "SELECT AddOverviewConstraints('%s','%s','%s','%s','%s','%s',%d);",
1303  (_ovschema != NULL ? _ovschema : ""),
1304  _ovtable,
1305  _ovcolumn,
1306  (_schema != NULL ? _schema : ""),
1307  _table,
1308  _column,
1309  factor
1310  );
1311 
1312  if (_ovschema != NULL)
1313  rtdealloc(_ovschema);
1314  rtdealloc(_ovtable);
1315  rtdealloc(_ovcolumn);
1316 
1317  if (_schema != NULL)
1318  rtdealloc(_schema);
1319  rtdealloc(_table);
1320  rtdealloc(_column);
1321 
1322  append_sql_to_buffer(buffer, sql);
1323 
1324  return 1;
1325 }
1326 
1327 static int
1328 build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, uint32_t ovx, STRINGBUFFER *tileset, STRINGBUFFER *buffer) {
1329  GDALDatasetH hdsSrc;
1330  VRTDatasetH hdsOv;
1331  VRTSourcedRasterBandH hbandOv;
1332  double gtOv[6] = {0.};
1333  int dimOv[2] = {0};
1334 
1335  uint32_t j = 0;
1336  int factor;
1337  const char *ovtable = NULL;
1338 
1339  VRTDatasetH hdsDst;
1340  VRTSourcedRasterBandH hbandDst;
1341  int tile_size[2] = {0};
1342  int _tile_size[2] = {0};
1343  int ntiles[2] = {1, 1};
1344  int xtile = 0;
1345  int ytile = 0;
1346  double gt[6] = {0.};
1347 
1348  rt_raster rast = NULL;
1349  char *hex;
1350  uint32_t hexlen = 0;
1351 
1352  hdsSrc = GDALOpenShared(config->rt_file[idx], GA_ReadOnly);
1353  if (hdsSrc == NULL) {
1354  rterror(_("build_overview: Could not open raster: %s"), config->rt_file[idx]);
1355  return 0;
1356  }
1357 
1358  /* working copy of geotransform matrix */
1359  memcpy(gtOv, info->gt, sizeof(double) * 6);
1360 
1361  if (ovx >= config->overview_count) {
1362  rterror(_("build_overview: Invalid overview index: %d"), ovx);
1363  return 0;
1364  }
1365  factor = config->overview[ovx];
1366  ovtable = (const char *) config->overview_table[ovx];
1367 
1368  /* factor must be within valid range */
1369  if (factor < MINOVFACTOR || factor > MAXOVFACTOR) {
1370  rterror(_("build_overview: Overview factor %d is not between %d and %d"), factor, MINOVFACTOR, MAXOVFACTOR);
1371  return 0;
1372  }
1373 
1374  dimOv[0] = (int) (info->dim[0] + (factor / 2)) / factor;
1375  dimOv[1] = (int) (info->dim[1] + (factor / 2)) / factor;
1376 
1377  /* create VRT dataset */
1378  hdsOv = VRTCreate(dimOv[0], dimOv[1]);
1379  /*
1380  GDALSetDescription(hdsOv, "/tmp/ov.vrt");
1381  */
1382  GDALSetProjection(hdsOv, info->srs);
1383 
1384  /* adjust scale */
1385  gtOv[1] *= factor;
1386  gtOv[5] *= factor;
1387 
1388  GDALSetGeoTransform(hdsOv, gtOv);
1389 
1390  /* add bands as simple sources */
1391  for (j = 0; j < info->nband_count; j++) {
1392  GDALAddBand(hdsOv, info->gdalbandtype[j], NULL);
1393  hbandOv = (VRTSourcedRasterBandH) GDALGetRasterBand(hdsOv, j + 1);
1394 
1395  if (info->hasnodata[j])
1396  GDALSetRasterNoDataValue(hbandOv, info->nodataval[j]);
1397 
1398  VRTAddSimpleSource(
1399  hbandOv, GDALGetRasterBand(hdsSrc, info->nband[j]),
1400  0, 0,
1401  info->dim[0], info->dim[1],
1402  0, 0,
1403  dimOv[0], dimOv[1],
1404  "near", VRT_NODATA_UNSET
1405  );
1406  }
1407 
1408  /* make sure VRT reflects all changes */
1409  VRTFlushCache(hdsOv);
1410 
1411  /* decide on tile size */
1412  if (!config->tile_size[0])
1413  tile_size[0] = dimOv[0];
1414  else
1415  tile_size[0] = config->tile_size[0];
1416  if (!config->tile_size[1])
1417  tile_size[1] = dimOv[1];
1418  else
1419  tile_size[1] = config->tile_size[1];
1420 
1421  /* number of tiles */
1422  if (
1423  tile_size[0] != dimOv[0] &&
1424  tile_size[1] != dimOv[1]
1425  ) {
1426  ntiles[0] = (dimOv[0] + tile_size[0] - 1) / tile_size[0];
1427  ntiles[1] = (dimOv[1] + tile_size[1] - 1) / tile_size[1];
1428  }
1429 
1430  /* working copy of geotransform matrix */
1431  memcpy(gt, gtOv, sizeof(double) * 6);
1432 
1433  /* tile overview */
1434  /* each tile is a VRT with constraints set for just the data required for the tile */
1435  for (ytile = 0; ytile < ntiles[1]; ytile++) {
1436 
1437  /* edge y tile */
1438  if (!config->pad_tile && ntiles[1] > 1 && (ytile + 1) == ntiles[1])
1439  _tile_size[1] = dimOv[1] - (ytile * tile_size[1]);
1440  else
1441  _tile_size[1] = tile_size[1];
1442 
1443  for (xtile = 0; xtile < ntiles[0]; xtile++) {
1444  /*
1445  char fn[100];
1446  sprintf(fn, "/tmp/ovtile%d.vrt", (ytile * ntiles[0]) + xtile);
1447  */
1448 
1449  /* edge x tile */
1450  if (!config->pad_tile && ntiles[0] > 1 && (xtile + 1) == ntiles[0])
1451  _tile_size[0] = dimOv[0] - (xtile * tile_size[0]);
1452  else
1453  _tile_size[0] = tile_size[0];
1454 
1455  /* compute tile's upper-left corner */
1456  GDALApplyGeoTransform(
1457  gtOv,
1458  xtile * tile_size[0], ytile * tile_size[1],
1459  &(gt[0]), &(gt[3])
1460  );
1461 
1462  /* create VRT dataset */
1463  hdsDst = VRTCreate(_tile_size[0], _tile_size[1]);
1464  /*
1465  GDALSetDescription(hdsDst, fn);
1466  */
1467  GDALSetProjection(hdsDst, info->srs);
1468  GDALSetGeoTransform(hdsDst, gt);
1469 
1470  /* add bands as simple sources */
1471  for (j = 0; j < info->nband_count; j++) {
1472  GDALAddBand(hdsDst, info->gdalbandtype[j], NULL);
1473  hbandDst = (VRTSourcedRasterBandH) GDALGetRasterBand(hdsDst, j + 1);
1474 
1475  if (info->hasnodata[j])
1476  GDALSetRasterNoDataValue(hbandDst, info->nodataval[j]);
1477 
1478  VRTAddSimpleSource(
1479  hbandDst, GDALGetRasterBand(hdsOv, j + 1),
1480  xtile * tile_size[0], ytile * tile_size[1],
1481  _tile_size[0], _tile_size[1],
1482  0, 0,
1483  _tile_size[0], _tile_size[1],
1484  "near", VRT_NODATA_UNSET
1485  );
1486  }
1487 
1488  /* make sure VRT reflects all changes */
1489  VRTFlushCache(hdsDst);
1490 
1491  /* convert VRT dataset to rt_raster */
1493  if (rast == NULL) {
1494  rterror(_("build_overview: Could not convert VRT dataset to PostGIS raster"));
1495  GDALClose(hdsDst);
1496  return 0;
1497  }
1498 
1499  /* set srid if provided */
1500  rt_raster_set_srid(rast, info->srid);
1501 
1502  /* convert rt_raster to hexwkb */
1503  hex = rt_raster_to_hexwkb(rast, FALSE, &hexlen);
1505 
1506  if (hex == NULL) {
1507  rterror(_("build_overview: Could not convert PostGIS raster to hex WKB"));
1508  GDALClose(hdsDst);
1509  return 0;
1510  }
1511 
1512  /* add hexwkb to tileset */
1513  append_stringbuffer(tileset, hex);
1514 
1515  GDALClose(hdsDst);
1516 
1517  /* flush if tileset gets too big */
1518  if (tileset->length > 10) {
1519  if (!insert_records(
1520  config->schema, ovtable, config->raster_column,
1521  (config->file_column ? config->rt_filename[idx] : NULL), config->file_column_name,
1522  config->copy_statements, config->out_srid,
1523  tileset, buffer
1524  )) {
1525  rterror(_("build_overview: Could not convert raster tiles into INSERT or COPY statements"));
1526  GDALClose(hdsSrc);
1527  return 0;
1528  }
1529 
1530  rtdealloc_stringbuffer(tileset, 0);
1531  }
1532  }
1533  }
1534 
1535  GDALClose(hdsOv);
1536  GDALClose(hdsSrc);
1537  return 1;
1538 }
1539 
1540 static int
1541 convert_raster(int idx, RTLOADERCFG *config, RASTERINFO *info, STRINGBUFFER *tileset, STRINGBUFFER *buffer) {
1542  GDALDatasetH hdsSrc;
1543  GDALRasterBandH hbandSrc;
1544  int nband = 0;
1545  uint32_t i = 0;
1546  int ntiles[2] = {1, 1};
1547  int _tile_size[2] = {0, 0};
1548  int xtile = 0;
1549  int ytile = 0;
1550  int naturalx = 1;
1551  int naturaly = 1;
1552  double gt[6] = {0.};
1553  const char* pszProjectionRef = NULL;
1554  int tilesize = 0;
1555 
1556  rt_raster rast = NULL;
1557  uint32_t numbands = 0;
1558  rt_band band = NULL;
1559  char *hex;
1560  uint32_t hexlen = 0;
1561 
1562  info->srid = config->srid;
1563 
1564  hdsSrc = GDALOpenShared(config->rt_file[idx], GA_ReadOnly);
1565  if (hdsSrc == NULL) {
1566  rterror(_("convert_raster: Could not open raster: %s"), config->rt_file[idx]);
1567  return 0;
1568  }
1569 
1570  nband = GDALGetRasterCount(hdsSrc);
1571  if (!nband) {
1572  rterror(_("convert_raster: No bands found in raster: %s"), config->rt_file[idx]);
1573  GDALClose(hdsSrc);
1574  return 0;
1575  }
1576 
1577  /* check that bands specified are available */
1578  for (i = 0; i < config->nband_count; i++) {
1579  if (config->nband[i] > nband) {
1580  rterror(_("convert_raster: Band %d not found in raster: %s"), config->nband[i], config->rt_file[idx]);
1581  GDALClose(hdsSrc);
1582  return 0;
1583  }
1584  }
1585 
1586  /* record srs */
1587  pszProjectionRef = GDALGetProjectionRef(hdsSrc);
1588  if (pszProjectionRef != NULL && pszProjectionRef[0] != '\0') {
1589  info->srs = rtalloc(sizeof(char) * (strlen(pszProjectionRef) + 1));
1590  if (info->srs == NULL) {
1591  rterror(_("convert_raster: Could not allocate memory for storing SRS"));
1592  GDALClose(hdsSrc);
1593  return 0;
1594  }
1595  strcpy(info->srs, pszProjectionRef);
1596 
1597  if (info->srid == SRID_UNKNOWN) {
1598  OGRSpatialReferenceH hSRS = OSRNewSpatialReference(NULL);
1599  if (OSRSetFromUserInput(hSRS, pszProjectionRef) == OGRERR_NONE) {
1600  const char* pszAuthorityName = OSRGetAuthorityName(hSRS, NULL);
1601  const char* pszAuthorityCode = OSRGetAuthorityCode(hSRS, NULL);
1602  if (
1603  pszAuthorityName != NULL &&
1604  strcmp(pszAuthorityName, "EPSG") == 0 &&
1605  pszAuthorityCode != NULL
1606  ) {
1607  info->srid = atoi(pszAuthorityCode);
1608  }
1609  }
1610  OSRDestroySpatialReference(hSRS);
1611  }
1612  }
1613 
1614  if ( info->srid == SRID_UNKNOWN && config->out_srid != SRID_UNKNOWN ) {
1615  rterror(_("convert_raster: could not determine source srid, cannot transform to target srid %d"), config->out_srid);
1616  GDALClose(hdsSrc);
1617  return 0;
1618  }
1619 
1620  /* record geotransform matrix */
1621  if (GDALGetGeoTransform(hdsSrc, info->gt) != CE_None) {
1622  rtinfo(_("Using default geotransform matrix (0, 1, 0, 0, 0, -1) for raster: %s"), config->rt_file[idx]);
1623  info->gt[0] = 0;
1624  info->gt[1] = 1;
1625  info->gt[2] = 0;
1626  info->gt[3] = 0;
1627  info->gt[4] = 0;
1628  info->gt[5] = -1;
1629  }
1630  memcpy(gt, info->gt, sizeof(double) * 6);
1631 
1632  /* record # of bands */
1633  /* user-specified bands */
1634  if (config->nband_count > 0) {
1635  info->nband_count = config->nband_count;
1636  info->nband = rtalloc(sizeof(int) * info->nband_count);
1637  if (info->nband == NULL) {
1638  rterror(_("convert_raster: Could not allocate memory for storing band indices"));
1639  GDALClose(hdsSrc);
1640  return 0;
1641  }
1642  memcpy(info->nband, config->nband, sizeof(int) * info->nband_count);
1643  }
1644  /* all bands */
1645  else {
1646  info->nband_count = nband;
1647  info->nband = rtalloc(sizeof(int) * info->nband_count);
1648  if (info->nband == NULL) {
1649  rterror(_("convert_raster: Could not allocate memory for storing band indices"));
1650  GDALClose(hdsSrc);
1651  return 0;
1652  }
1653  for (i = 0; i < info->nband_count; i++)
1654  info->nband[i] = i + 1;
1655  }
1656 
1657  /* initialize parameters dependent on nband */
1658  info->gdalbandtype = rtalloc(sizeof(GDALDataType) * info->nband_count);
1659  if (info->gdalbandtype == NULL) {
1660  rterror(_("convert_raster: Could not allocate memory for storing GDAL data type"));
1661  GDALClose(hdsSrc);
1662  return 0;
1663  }
1664  info->bandtype = rtalloc(sizeof(rt_pixtype) * info->nband_count);
1665  if (info->bandtype == NULL) {
1666  rterror(_("convert_raster: Could not allocate memory for storing pixel type"));
1667  GDALClose(hdsSrc);
1668  return 0;
1669  }
1670  info->hasnodata = rtalloc(sizeof(int) * info->nband_count);
1671  if (info->hasnodata == NULL) {
1672  rterror(_("convert_raster: Could not allocate memory for storing hasnodata flag"));
1673  GDALClose(hdsSrc);
1674  return 0;
1675  }
1676  info->nodataval = rtalloc(sizeof(double) * info->nband_count);
1677  if (info->nodataval == NULL) {
1678  rterror(_("convert_raster: Could not allocate memory for storing nodata value"));
1679  GDALClose(hdsSrc);
1680  return 0;
1681  }
1682  memset(info->gdalbandtype, GDT_Unknown, sizeof(GDALDataType) * info->nband_count);
1683  memset(info->bandtype, PT_END, sizeof(rt_pixtype) * info->nband_count);
1684  memset(info->hasnodata, 0, sizeof(int) * info->nband_count);
1685  memset(info->nodataval, 0, sizeof(double) * info->nband_count);
1686 
1687  /* dimensions of raster */
1688  info->dim[0] = GDALGetRasterXSize(hdsSrc);
1689  info->dim[1] = GDALGetRasterYSize(hdsSrc);
1690 
1691  tilesize = 0;
1692 
1693  /* go through bands for attributes */
1694  for (i = 0; i < info->nband_count; i++) {
1695  hbandSrc = GDALGetRasterBand(hdsSrc, info->nband[i]);
1696 
1697  /* datatype */
1698  info->gdalbandtype[i] = GDALGetRasterDataType(hbandSrc);
1699 
1700  /* complex data type? */
1701  if (GDALDataTypeIsComplex(info->gdalbandtype[i])) {
1702  rterror(_("convert_raster: The pixel type of band %d is a complex data type. PostGIS raster does not support complex data types"), i + 1);
1703  GDALClose(hdsSrc);
1704  return 0;
1705  }
1706  GDALGetBlockSize(hbandSrc, &naturalx, &naturaly);
1707 
1708  /* convert data type to that of postgis raster */
1710 
1711  /* hasnodata and nodataval */
1712  info->nodataval[i] = GDALGetRasterNoDataValue(hbandSrc, &(info->hasnodata[i]));
1713  if (!info->hasnodata[i]) {
1714  /* does NOT have nodata value, but user-specified */
1715  if (config->hasnodata) {
1716  info->hasnodata[i] = 1;
1717  info->nodataval[i] = config->nodataval;
1718  }
1719  else
1720  info->nodataval[i] = 0;
1721  }
1722 
1723  /* update estimated byte size of 1 pixel */
1724  tilesize += rt_pixtype_size(info->bandtype[i]);
1725  }
1726 
1727  /* tile size is "auto" */
1728  if (config->tile_size[0] == -1 && config->tile_size[1] == -1)
1729  {
1730  calc_tile_size((naturalx > 1) ? (uint32_t)naturalx : info->dim[0],
1731  (naturaly > 1) ? (uint32_t)naturaly : info->dim[1],
1732  &(config->tile_size[0]),
1733  &(config->tile_size[1]));
1734 
1735  rtinfo(_("Using computed tile size: %dx%d"), config->tile_size[0], config->tile_size[1]);
1736  }
1737 
1738  /* decide on tile size */
1739  if (!config->tile_size[0])
1740  info->tile_size[0] = info->dim[0];
1741  else
1742  info->tile_size[0] = config->tile_size[0];
1743  if (!config->tile_size[1])
1744  info->tile_size[1] = info->dim[1];
1745  else
1746  info->tile_size[1] = config->tile_size[1];
1747 
1748  /* number of tiles */
1749  if ((uint32_t)info->tile_size[0] != info->dim[0])
1750  ntiles[0] = (info->dim[0] + info->tile_size[0] - 1) / info->tile_size[0];
1751  if ((uint32_t)info->tile_size[1] != info->dim[1])
1752  ntiles[1] = (info->dim[1] + info->tile_size[1] - 1) / info->tile_size[1];
1753 
1754  /* estimate size of 1 tile */
1755  tilesize *= info->tile_size[0] * info->tile_size[1];
1756 
1757  /* roughly estimate size of one tile and all bands */
1758  tilesize *= 1.1;
1759  if (tilesize > MAXTILESIZE)
1760  rtwarn(_("The size of each output tile may exceed 1 GB. Use -t to specify a reasonable tile size"));
1761 
1762  /* out-db raster */
1763  if (config->outdb) {
1764  GDALClose(hdsSrc);
1765 
1766  /* each tile is a raster */
1767  for (ytile = 0; ytile < ntiles[1]; ytile++) {
1768  /* edge y tile */
1769  if (!config->pad_tile && ntiles[1] > 1 && (ytile + 1) == ntiles[1])
1770  _tile_size[1] = info->dim[1] - (ytile * info->tile_size[1]);
1771  else
1772  _tile_size[1] = info->tile_size[1];
1773 
1774  for (xtile = 0; xtile < ntiles[0]; xtile++) {
1775  int tile_is_nodata = !config->skip_nodataval_check;
1776 
1777  /* edge x tile */
1778  if (!config->pad_tile && ntiles[0] > 1 && (xtile + 1) == ntiles[0])
1779  _tile_size[0] = info->dim[0] - (xtile * info->tile_size[0]);
1780  else
1781  _tile_size[0] = info->tile_size[0];
1782 
1783  /* compute tile's upper-left corner */
1784  GDALApplyGeoTransform(
1785  info->gt,
1786  xtile * info->tile_size[0], ytile * info->tile_size[1],
1787  &(gt[0]), &(gt[3])
1788  );
1789 
1790  /* create raster object */
1791  rast = rt_raster_new(_tile_size[0], _tile_size[1]);
1792  if (rast == NULL) {
1793  rterror(_("convert_raster: Could not create raster"));
1794  return 0;
1795  }
1796 
1797  /* set raster attributes */
1798  rt_raster_set_srid(rast, info->srid);
1800 
1801  /* add bands */
1802  for (i = 0; i < info->nband_count; i++) {
1804  _tile_size[0], _tile_size[1],
1805  info->bandtype[i],
1806  info->hasnodata[i], info->nodataval[i],
1807  info->nband[i] - 1,
1808  config->rt_file[idx]
1809  );
1810  if (band == NULL) {
1811  rterror(_("convert_raster: Could not create offline band"));
1813  return 0;
1814  }
1815 
1816  /* add band to raster */
1818  rterror(_("convert_raster: Could not add offlineband to raster"));
1821  return 0;
1822  }
1823 
1824  /* inspect each band of raster where band is NODATA */
1825  if (!config->skip_nodataval_check)
1826  tile_is_nodata = tile_is_nodata && rt_band_check_is_nodata(band);
1827  }
1828 
1829  /* convert rt_raster to hexwkb */
1830  if (!tile_is_nodata)
1831  hex = rt_raster_to_hexwkb(rast, FALSE, &hexlen);
1833 
1834  if (!hex && !tile_is_nodata)
1835  {
1836  rterror(_("convert_raster: Could not convert PostGIS raster to hex WKB"));
1837  return 0;
1838  }
1839 
1840  /* add hexwkb to tileset */
1841  if (!tile_is_nodata)
1842  append_stringbuffer(tileset, hex);
1843 
1844  /* flush if tileset gets too big */
1845  if (tileset->length > 10) {
1846  if (!insert_records(
1847  config->schema, config->table, config->raster_column,
1848  (config->file_column ? config->rt_filename[idx] : NULL), config->file_column_name,
1849  config->copy_statements, config->out_srid,
1850  tileset, buffer
1851  )) {
1852  rterror(_("convert_raster: Could not convert raster tiles into INSERT or COPY statements"));
1853  return 0;
1854  }
1855 
1856  rtdealloc_stringbuffer(tileset, 0);
1857  }
1858  }
1859  }
1860  }
1861  /* in-db raster */
1862  else {
1863  VRTDatasetH hdsDst;
1864  VRTSourcedRasterBandH hbandDst;
1865 
1866  /* each tile is a VRT with constraints set for just the data required for the tile */
1867  for (ytile = 0; ytile < ntiles[1]; ytile++) {
1868 
1869  /* edge y tile */
1870  if (!config->pad_tile && ntiles[1] > 1 && (ytile + 1) == ntiles[1])
1871  _tile_size[1] = info->dim[1] - (ytile * info->tile_size[1]);
1872  else
1873  _tile_size[1] = info->tile_size[1];
1874 
1875  for (xtile = 0; xtile < ntiles[0]; xtile++) {
1876  int tile_is_nodata = !config->skip_nodataval_check;
1877  /*
1878  char fn[100];
1879  sprintf(fn, "/tmp/tile%d.vrt", (ytile * ntiles[0]) + xtile);
1880  */
1881 
1882  /* edge x tile */
1883  if (!config->pad_tile && ntiles[0] > 1 && (xtile + 1) == ntiles[0])
1884  _tile_size[0] = info->dim[0] - (xtile * info->tile_size[0]);
1885  else
1886  _tile_size[0] = info->tile_size[0];
1887 
1888  /* compute tile's upper-left corner */
1889  GDALApplyGeoTransform(
1890  info->gt,
1891  xtile * info->tile_size[0], ytile * info->tile_size[1],
1892  &(gt[0]), &(gt[3])
1893  );
1894  /*
1895  rtinfo(_("tile (%d, %d) gt = (%f, %f, %f, %f, %f, %f)"),
1896  xtile, ytile,
1897  gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]
1898  );
1899  */
1900 
1901  /* create VRT dataset */
1902  hdsDst = VRTCreate(_tile_size[0], _tile_size[1]);
1903  /*
1904  GDALSetDescription(hdsDst, fn);
1905  */
1906  GDALSetProjection(hdsDst, info->srs);
1907  GDALSetGeoTransform(hdsDst, gt);
1908 
1909  /* add bands as simple sources */
1910  for (i = 0; i < info->nband_count; i++) {
1911  GDALAddBand(hdsDst, info->gdalbandtype[i], NULL);
1912  hbandDst = (VRTSourcedRasterBandH) GDALGetRasterBand(hdsDst, i + 1);
1913 
1914  if (info->hasnodata[i])
1915  GDALSetRasterNoDataValue(hbandDst, info->nodataval[i]);
1916 
1917  VRTAddSimpleSource(
1918  hbandDst, GDALGetRasterBand(hdsSrc, info->nband[i]),
1919  xtile * info->tile_size[0], ytile * info->tile_size[1],
1920  _tile_size[0], _tile_size[1],
1921  0, 0,
1922  _tile_size[0], _tile_size[1],
1923  "near", VRT_NODATA_UNSET
1924  );
1925  }
1926 
1927  /* make sure VRT reflects all changes */
1928  VRTFlushCache(hdsDst);
1929 
1930  /* convert VRT dataset to rt_raster */
1932  if (rast == NULL) {
1933  rterror(_("convert_raster: Could not convert VRT dataset to PostGIS raster"));
1934  GDALClose(hdsDst);
1935  return 0;
1936  }
1937 
1938  /* set srid if provided */
1939  rt_raster_set_srid(rast, info->srid);
1940 
1941  /* inspect each band of raster where band is NODATA */
1942  numbands = rt_raster_get_num_bands(rast);
1943  for (i = 0; i < numbands; i++) {
1945  if (band != NULL && !config->skip_nodataval_check)
1946  tile_is_nodata = tile_is_nodata && rt_band_check_is_nodata(band);
1947  }
1948 
1949  /* convert rt_raster to hexwkb */
1950  if (!tile_is_nodata)
1951  hex = rt_raster_to_hexwkb(rast, FALSE, &hexlen);
1953 
1954  if (!hex && !tile_is_nodata)
1955  {
1956  rterror(_("convert_raster: Could not convert PostGIS raster to hex WKB"));
1957  GDALClose(hdsDst);
1958  return 0;
1959  }
1960 
1961  /* add hexwkb to tileset */
1962  if (!tile_is_nodata)
1963  append_stringbuffer(tileset, hex);
1964 
1965  GDALClose(hdsDst);
1966 
1967  /* flush if tileset gets too big */
1968  if (tileset->length > 10) {
1969  if (!insert_records(
1970  config->schema, config->table, config->raster_column,
1971  (config->file_column ? config->rt_filename[idx] : NULL), config->file_column_name,
1972  config->copy_statements, config->out_srid,
1973  tileset, buffer
1974  )) {
1975  rterror(_("convert_raster: Could not convert raster tiles into INSERT or COPY statements"));
1976  GDALClose(hdsSrc);
1977  return 0;
1978  }
1979 
1980  rtdealloc_stringbuffer(tileset, 0);
1981  }
1982  }
1983  }
1984 
1985  GDALClose(hdsSrc);
1986  }
1987 
1988  return 1;
1989 }
1990 
1991 static int
1992 process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) {
1993  uint32_t i = 0;
1994 
1995  assert(config != NULL);
1996  assert(config->table != NULL);
1997  assert(config->raster_column != NULL);
1998 
1999  if (config->transaction) {
2000  if (!append_sql_to_buffer(buffer, strdup("BEGIN;"))) {
2001  rterror(_("process_rasters: Could not add BEGIN statement to string buffer"));
2002  return 0;
2003  }
2004  }
2005 
2006  /* drop table */
2007  if (config->opt == 'd') {
2008  if (!drop_table(config->schema, config->table, buffer)) {
2009  rterror(_("process_rasters: Could not add DROP TABLE statement to string buffer"));
2010  return 0;
2011  }
2012 
2013  if (config->overview_count) {
2014  for (i = 0; i < config->overview_count; i++) {
2015  if (!drop_table(config->schema, config->overview_table[i], buffer)) {
2016  rterror(_("process_rasters: Could not add an overview's DROP TABLE statement to string buffer"));
2017  return 0;
2018  }
2019  }
2020  }
2021  }
2022 
2023  /* create table */
2024  if (config->opt != 'a') {
2025  if (!create_table(
2026  config->schema, config->table, config->raster_column,
2027  config->file_column, config->file_column_name,
2028  config->tablespace, config->idx_tablespace,
2029  buffer
2030  )) {
2031  rterror(_("process_rasters: Could not add CREATE TABLE statement to string buffer"));
2032  return 0;
2033  }
2034 
2035  if (config->overview_count) {
2036  for (i = 0; i < config->overview_count; i++) {
2037  if (!create_table(
2038  config->schema, config->overview_table[i], config->raster_column,
2039  config->file_column, config->file_column_name,
2040  config->tablespace, config->idx_tablespace,
2041  buffer
2042  )) {
2043  rterror(_("process_rasters: Could not add an overview's CREATE TABLE statement to string buffer"));
2044  return 0;
2045  }
2046  }
2047  }
2048  }
2049 
2050  /* no need to run if opt is 'p' */
2051  if (config->opt != 'p') {
2052  RASTERINFO refinfo;
2053  init_rastinfo(&refinfo);
2054 
2055  /* process each raster */
2056  for (i = 0; i < config->rt_file_count; i++) {
2057  RASTERINFO rastinfo;
2058  STRINGBUFFER tileset;
2059 
2060  fprintf(stderr, _("Processing %d/%d: %s\n"), i + 1, config->rt_file_count, config->rt_file[i]);
2061 
2062  init_rastinfo(&rastinfo);
2063  init_stringbuffer(&tileset);
2064 
2065  /* convert raster */
2066  if (!convert_raster(i, config, &rastinfo, &tileset, buffer)) {
2067  rterror(_("process_rasters: Could not process raster: %s"), config->rt_file[i]);
2068  rtdealloc_rastinfo(&rastinfo);
2069  rtdealloc_stringbuffer(&tileset, 0);
2070  return 0;
2071  }
2072 
2073  /* process raster tiles into COPY or INSERT statements */
2074  if (tileset.length && !insert_records(
2075  config->schema, config->table, config->raster_column,
2076  (config->file_column ? config->rt_filename[i] : NULL),
2077  config->file_column_name,
2078  config->copy_statements, config->out_srid,
2079  &tileset, buffer
2080  )) {
2081  rterror(_("process_rasters: Could not convert raster tiles into INSERT or COPY statements"));
2082  rtdealloc_rastinfo(&rastinfo);
2083  rtdealloc_stringbuffer(&tileset, 0);
2084  return 0;
2085  }
2086 
2087  rtdealloc_stringbuffer(&tileset, 0);
2088 
2089  /* flush buffer after every raster */
2090  flush_stringbuffer(buffer);
2091 
2092  /* overviews */
2093  if (config->overview_count) {
2094  uint32_t j = 0;
2095 
2096  for (j = 0; j < config->overview_count; j++) {
2097 
2098  if (!build_overview(i, config, &rastinfo, j, &tileset, buffer)) {
2099  rterror(_("process_rasters: Could not create overview of factor %d for raster %s"), config->overview[j], config->rt_file[i]);
2100  rtdealloc_rastinfo(&rastinfo);
2101  rtdealloc_stringbuffer(&tileset, 0);
2102  return 0;
2103  }
2104 
2105  if (tileset.length && !insert_records(
2106  config->schema, config->overview_table[j], config->raster_column,
2107  (config->file_column ? config->rt_filename[i] : NULL), config->file_column_name,
2108  config->copy_statements, config->out_srid,
2109  &tileset, buffer
2110  )) {
2111  rterror(_("process_rasters: Could not convert overview tiles into INSERT or COPY statements"));
2112  rtdealloc_rastinfo(&rastinfo);
2113  rtdealloc_stringbuffer(&tileset, 0);
2114  return 0;
2115  }
2116 
2117  rtdealloc_stringbuffer(&tileset, 0);
2118 
2119  /* flush buffer after every raster */
2120  flush_stringbuffer(buffer);
2121  }
2122  }
2123 
2124  if (config->rt_file_count > 1) {
2125  if (i < 1)
2126  copy_rastinfo(&refinfo, &rastinfo);
2127  else {
2128  diff_rastinfo(&rastinfo, &refinfo);
2129  }
2130  }
2131 
2132  rtdealloc_rastinfo(&rastinfo);
2133  }
2134 
2135  rtdealloc_rastinfo(&refinfo);
2136  }
2137 
2138  /* index */
2139  if (config->idx) {
2140  /* create index */
2141  if (!create_index(
2142  config->schema, config->table, config->raster_column,
2143  config->idx_tablespace,
2144  buffer
2145  )) {
2146  rterror(_("process_rasters: Could not add CREATE INDEX statement to string buffer"));
2147  return 0;
2148  }
2149 
2150  /* analyze */
2151  if (config->opt != 'p') {
2152  if (!analyze_table(
2153  config->schema, config->table,
2154  buffer
2155  )) {
2156  rterror(_("process_rasters: Could not add ANALYZE statement to string buffer"));
2157  return 0;
2158  }
2159  }
2160 
2161  if (config->overview_count) {
2162  for (i = 0; i < config->overview_count; i++) {
2163  /* create index */
2164  if (!create_index(
2165  config->schema, config->overview_table[i], config->raster_column,
2166  config->idx_tablespace,
2167  buffer
2168  )) {
2169  rterror(_("process_rasters: Could not add an overview's CREATE INDEX statement to string buffer"));
2170  return 0;
2171  }
2172 
2173  /* analyze */
2174  if (config->opt != 'p') {
2175  if (!analyze_table(
2176  config->schema, config->overview_table[i],
2177  buffer
2178  )) {
2179  rterror(_("process_rasters: Could not add an overview's ANALYZE statement to string buffer"));
2180  return 0;
2181  }
2182  }
2183  }
2184  }
2185  }
2186 
2187  /* add constraints */
2188  if (config->constraints) {
2189  if (!add_raster_constraints(
2190  config->schema, config->table, config->raster_column,
2191  config->regular_blocking, config->max_extent,
2192  buffer
2193  )) {
2194  rterror(_("process:rasters: Could not add AddRasterConstraints statement to string buffer"));
2195  return 0;
2196  }
2197 
2198  if (config->overview_count) {
2199  for (i = 0; i < config->overview_count; i++) {
2200  if (!add_raster_constraints(
2201  config->schema, config->overview_table[i], config->raster_column,
2202  config->regular_blocking, config->max_extent,
2203  buffer
2204  )) {
2205  rterror(_("process_rasters: Could not add an overview's AddRasterConstraints statement to string buffer"));
2206  return 0;
2207  }
2208  }
2209  }
2210  }
2211 
2212  /* overview constraint is automatically added */
2213  if (config->overview_count) {
2214  for (i = 0; i < config->overview_count; i++) {
2215  if (!add_overview_constraints(
2216  config->schema, config->overview_table[i], config->raster_column,
2217  config->schema, config->table, config->raster_column,
2218  config->overview[i],
2219  buffer
2220  )) {
2221  rterror(_("process_rasters: Could not add an overview's AddOverviewConstraints statement to string buffer"));
2222  return 0;
2223  }
2224  }
2225  }
2226 
2227  if (config->transaction) {
2228  if (!append_sql_to_buffer(buffer, strdup("END;"))) {
2229  rterror(_("process_rasters: Could not add END statement to string buffer"));
2230  return 0;
2231  }
2232  }
2233 
2234  /* maintenance */
2235  if (config->opt != 'p' && config->maintenance) {
2236  if (!vacuum_table(
2237  config->schema, config->table,
2238  buffer
2239  )) {
2240  rterror(_("process_rasters: Could not add VACUUM statement to string buffer"));
2241  return 0;
2242  }
2243 
2244  if (config->overview_count) {
2245  for (i = 0; i < config->overview_count; i++) {
2246  if (!vacuum_table(
2247  config->schema, config->overview_table[i],
2248  buffer
2249  )) {
2250  rterror(_("process_rasters: Could not add an overview's VACUUM statement to string buffer"));
2251  return 0;
2252  }
2253  }
2254  }
2255 
2256  }
2257 
2258  return 1;
2259 }
2260 
2261 int
2262 main(int argc, char **argv) {
2263  RTLOADERCFG *config = NULL;
2264  STRINGBUFFER *buffer = NULL;
2265  uint32_t i = 0;
2266  uint32_t j = 0;
2267  char **elements = NULL;
2268  uint32_t n = 0;
2269  GDALDriverH drv = NULL;
2270  char *tmp = NULL;
2271  int argit = 0;
2272 
2274 
2275 #ifdef USE_NLS
2276  setlocale (LC_ALL, "");
2277  bindtextdomain (PACKAGE, LOCALEDIR);
2278  textdomain (PACKAGE);
2279 #endif
2280 
2281  /* no args, show usage */
2282  if (argc == 1) {
2283  usage();
2284  exit(0);
2285  }
2286 
2287  /* initialize config */
2288  config = rtalloc(sizeof(RTLOADERCFG));
2289  if (config == NULL) {
2290  rterror(_("Could not allocate memory for loader configuration"));
2291  exit(1);
2292  }
2293  init_config(config);
2294 
2295  /****************************************************************************
2296  * parse arguments
2297  ****************************************************************************/
2298 
2299  for (argit = 1; argit < argc; argit++) {
2300  char *optarg, *ptr;
2301  /* srid */
2302 
2303  if (CSEQUAL(argv[argit], "-s") && argit < argc - 1) {
2304  optarg = argv[++argit];
2305  ptr = strchr(optarg, ':');
2306  if (ptr) {
2307  *ptr++ = '\0';
2308  sscanf(optarg, "%d", &config->srid);
2309  sscanf(ptr, "%d", &config->out_srid);
2310  } else {
2311  config->srid = atoi(optarg);
2312  }
2313  }
2314  /* band index */
2315  else if (CSEQUAL(argv[argit], "-b") && argit < argc - 1) {
2316  elements = strsplit(argv[++argit], ",", &n);
2317  if (n < 1) {
2318  rterror(_("Could not process -b"));
2319  rtdealloc_config(config);
2320  exit(1);
2321  }
2322 
2323  config->nband_count = 0;
2324  for (j = 0; j < n; j++) {
2325  char *t = trim(elements[j]);
2326  char **minmax = NULL;
2327  int *range = NULL;
2328  uint32_t p = 0;
2329  uint32_t l = 0;
2330  int m = 0;
2331  uint32_t o = 0;
2332 
2333  /* is t a range? */
2334  minmax = strsplit(t, "-", &o);
2335  if (o == 2) {
2336  if (!array_range(atoi(minmax[0]), atoi(minmax[1]), 1, &range, &p)) {
2337  rterror(_("Could not allocate memory for storing band indices"));
2338  for (l = 0; l < o; l++)
2339  rtdealloc(minmax[l]);
2340  rtdealloc(minmax);
2341  for (j = 0; j < n; j++)
2342  rtdealloc(elements[j]);
2343  rtdealloc(elements);
2344  rtdealloc(t);
2345  rtdealloc_config(config);
2346  exit(1);
2347  }
2348  }
2349  else {
2350  p = 1;
2351  range = rtalloc(sizeof(int));
2352  if (range == NULL) {
2353  rterror(_("Could not allocate memory for storing band indices"));
2354  for (l = 0; l < o; l++)
2355  rtdealloc(minmax[l]);
2356  rtdealloc(minmax);
2357  for (j = 0; j < n; j++)
2358  rtdealloc(elements[j]);
2359  rtdealloc(elements);
2360  rtdealloc(t);
2361  rtdealloc_config(config);
2362  exit(1);
2363  }
2364  *range = atoi(t);
2365  }
2366 
2367  m = config->nband_count;
2368  config->nband_count += p;
2369  config->nband = rtrealloc(config->nband, sizeof(int) * config->nband_count);
2370  if (config->nband == NULL) {
2371  rterror(_("Could not allocate memory for storing band indices"));
2372  rtdealloc(range);
2373  for (l = 0; l < o; l++)
2374  rtdealloc(minmax[l]);
2375  rtdealloc(minmax);
2376  for (j = 0; j < n; j++)
2377  rtdealloc(elements[j]);
2378  rtdealloc(elements);
2379  rtdealloc(t);
2380  rtdealloc_config(config);
2381  exit(1);
2382  }
2383 
2384  for (l = 0; l < p; l++, m++)
2385  config->nband[m] = range[l];
2386 
2387  rtdealloc(range);
2388 
2389  for (l = 0; l < o; l++)
2390  rtdealloc(minmax[l]);
2391  rtdealloc(minmax);
2392 
2393  rtdealloc(t);
2394  rtdealloc(elements[j]);
2395  }
2396  rtdealloc(elements);
2397  elements = NULL;
2398  n = 0;
2399 
2400  for (j = 0; j < config->nband_count; j++) {
2401  if (config->nband[j] < 1) {
2402  rterror(_("Band index %d must be greater than 0"), config->nband[j]);
2403  rtdealloc_config(config);
2404  exit(1);
2405  }
2406  }
2407  }
2408  /* tile size */
2409  else if (CSEQUAL(argv[argit], "-t") && argit < argc - 1) {
2410  if (CSEQUAL(argv[++argit], "auto")) {
2411  config->tile_size[0] = -1;
2412  config->tile_size[1] = -1;
2413  }
2414  else {
2415  elements = strsplit(argv[argit], "x", &n);
2416  if (n != 2) {
2417  rterror(_("Could not process -t"));
2418  rtdealloc_config(config);
2419  exit(1);
2420  }
2421 
2422  for (j = 0; j < n; j++) {
2423  char *t = trim(elements[j]);
2424  config->tile_size[j] = atoi(t);
2425  rtdealloc(t);
2426  rtdealloc(elements[j]);
2427  }
2428  rtdealloc(elements);
2429  elements = NULL;
2430  n = 0;
2431 
2432  for (j = 0; j < 2; j++) {
2433  if (config->tile_size[j] < 1) {
2434  rterror(_("Tile size must be greater than 0x0"));
2435  rtdealloc_config(config);
2436  exit(1);
2437  }
2438  }
2439  }
2440  }
2441  /* pad tiles */
2442  else if (CSEQUAL(argv[argit], "-P")) {
2443  config->pad_tile = 1;
2444  }
2445  /* out-of-db raster */
2446  else if (CSEQUAL(argv[argit], "-R")) {
2447  config->outdb = 1;
2448  }
2449  /* drop table and recreate */
2450  else if (CSEQUAL(argv[argit], "-d")) {
2451  config->opt = 'd';
2452  }
2453  /* append to table */
2454  else if (CSEQUAL(argv[argit], "-a")) {
2455  config->opt = 'a';
2456  }
2457  /* create new table */
2458  else if (CSEQUAL(argv[argit], "-c")) {
2459  config->opt = 'c';
2460  }
2461  /* prepare only */
2462  else if (CSEQUAL(argv[argit], "-p")) {
2463  config->opt = 'p';
2464  }
2465  /* raster column name */
2466  else if (CSEQUAL(argv[argit], "-f") && argit < argc - 1) {
2467  const size_t len = (strlen(argv[++argit]) + 1);
2468  config->raster_column = rtalloc(sizeof(char) * len);
2469  if (config->raster_column == NULL) {
2470  rterror(_("Could not allocate memory for storing raster column name"));
2471  rtdealloc_config(config);
2472  exit(1);
2473  }
2474  strncpy(config->raster_column, argv[argit], len);
2475  }
2476  /* filename column */
2477  else if (CSEQUAL(argv[argit], "-F")) {
2478  config->file_column = 1;
2479  }
2480  /* filename column name */
2481  else if (CSEQUAL(argv[argit], "-n") && argit < argc - 1) {
2482  const size_t len = (strlen(argv[++argit]) + 1);
2483  config->file_column_name = rtalloc(sizeof(char) * len);
2484  if (config->file_column_name == NULL) {
2485  rterror(_("Could not allocate memory for storing filename column name"));
2486  rtdealloc_config(config);
2487  exit(1);
2488  }
2489  strncpy(config->file_column_name, argv[argit], len);
2490  config->file_column = 1;
2491  }
2492  /* overview factors */
2493  else if (CSEQUAL(argv[argit], "-l") && argit < argc - 1) {
2494  elements = strsplit(argv[++argit], ",", &n);
2495  if (n < 1) {
2496  rterror(_("Could not process -l"));
2497  rtdealloc_config(config);
2498  exit(1);
2499  }
2500 
2501  config->overview_count = n;
2502  config->overview = rtalloc(sizeof(int) * n);
2503  if (config->overview == NULL) {
2504  rterror(_("Could not allocate memory for storing overview factors"));
2505  rtdealloc_config(config);
2506  exit(1);
2507  }
2508  for (j = 0; j < n; j++) {
2509  char *t = trim(elements[j]);
2510  config->overview[j] = atoi(t);
2511  rtdealloc(t);
2512  rtdealloc(elements[j]);
2513  }
2514  rtdealloc(elements);
2515  elements = NULL;
2516  n = 0;
2517 
2518  for (j = 0; j < (uint32_t)config->overview_count; j++) {
2519  if (config->overview[j] < MINOVFACTOR || config->overview[j] > MAXOVFACTOR) {
2520  rterror(_("Overview factor %d is not between %d and %d"), config->overview[j], MINOVFACTOR, MAXOVFACTOR);
2521  rtdealloc_config(config);
2522  exit(1);
2523  }
2524  }
2525  }
2526  /* quote identifiers */
2527  else if (CSEQUAL(argv[argit], "-q")) {
2528  config->quoteident = 1;
2529  }
2530  /* create index */
2531  else if (CSEQUAL(argv[argit], "-I")) {
2532  config->idx = 1;
2533  }
2534  /* maintenance */
2535  else if (CSEQUAL(argv[argit], "-M")) {
2536  config->maintenance = 1;
2537  }
2538  /* set constraints */
2539  else if (CSEQUAL(argv[argit], "-C")) {
2540  config->constraints = 1;
2541  }
2542  /* disable extent constraint */
2543  else if (CSEQUAL(argv[argit], "-x")) {
2544  config->max_extent = 0;
2545  }
2546  /* enable regular_blocking */
2547  else if (CSEQUAL(argv[argit], "-r")) {
2548  config->regular_blocking = 1;
2549  }
2550  /* tablespace of new table */
2551  else if (CSEQUAL(argv[argit], "-T") && argit < argc - 1) {
2552  const size_t len = (strlen(argv[++argit]) + 1);
2553  config->tablespace = rtalloc(len);
2554  if (config->tablespace == NULL) {
2555  rterror(_("Could not allocate memory for storing tablespace of new table"));
2556  rtdealloc_config(config);
2557  exit(1);
2558  }
2559  strncpy(config->tablespace, argv[argit], len);
2560  }
2561  /* tablespace of new index */
2562  else if (CSEQUAL(argv[argit], "-X") && argit < argc - 1) {
2563  const size_t len = (strlen(argv[++argit]) + 1);
2564  config->idx_tablespace = rtalloc(len);
2565  if (config->idx_tablespace == NULL) {
2566  rterror(_("Could not allocate memory for storing tablespace of new indices"));
2567  rtdealloc_config(config);
2568  exit(1);
2569  }
2570  strncpy(config->idx_tablespace, argv[argit], len);
2571  }
2572  /* nodata value */
2573  else if (CSEQUAL(argv[argit], "-N") && argit < argc - 1) {
2574  config->hasnodata = 1;
2575  config->nodataval = atof(argv[++argit]);
2576  }
2577  /* skip NODATA value check for bands */
2578  else if (CSEQUAL(argv[argit], "-k")) {
2579  config->skip_nodataval_check = 1;
2580  }
2581  /* endianness */
2582  else if (CSEQUAL(argv[argit], "-E") && argit < argc - 1) {
2583  config->endian = atoi(argv[++argit]);
2584  config->endian = 1;
2585  }
2586  /* version */
2587  else if (CSEQUAL(argv[argit], "-V") && argit < argc - 1) {
2588  config->version = atoi(argv[++argit]);
2589  config->version = 0;
2590  }
2591  /* transaction */
2592  else if (CSEQUAL(argv[argit], "-e")) {
2593  config->transaction = 0;
2594  }
2595  /* COPY statements */
2596  else if (CSEQUAL(argv[argit], "-Y")) {
2597  config->copy_statements = 1;
2598  }
2599  /* GDAL formats */
2600  else if (CSEQUAL(argv[argit], "-G")) {
2601  uint32_t drv_count = 0;
2602  rt_gdaldriver drv_set = rt_raster_gdal_drivers(&drv_count, 0);
2603  if (drv_set == NULL || !drv_count) {
2604  rterror(_("Could not get list of available GDAL raster formats"));
2605  }
2606  else {
2607  printf(_("Supported GDAL raster formats:\n"));
2608  for (j = 0; j < drv_count; j++) {
2609  printf(_(" %s\n"), drv_set[j].long_name);
2610 
2611  rtdealloc(drv_set[j].short_name);
2612  rtdealloc(drv_set[j].long_name);
2613  rtdealloc(drv_set[j].create_options);
2614  }
2615  rtdealloc(drv_set);
2616  }
2617 
2618  rtdealloc_config(config);
2619  exit(0);
2620  }
2621  /* help */
2622  else if (CSEQUAL(argv[argit], "-?")) {
2623  usage();
2624  rtdealloc_config(config);
2625  exit(0);
2626  }
2627  else {
2628  size_t len;
2629  config->rt_file_count++;
2630  config->rt_file = (char **) rtrealloc(config->rt_file, sizeof(char *) * config->rt_file_count);
2631  if (config->rt_file == NULL) {
2632  rterror(_("Could not allocate memory for storing raster files"));
2633  rtdealloc_config(config);
2634  exit(1);
2635  }
2636 
2637  len = strlen(argv[argit]) + 1;
2638  config->rt_file[config->rt_file_count - 1] = rtalloc(sizeof(char) * len);
2639  if (config->rt_file[config->rt_file_count - 1] == NULL) {
2640  rterror(_("Could not allocate memory for storing raster filename"));
2641  rtdealloc_config(config);
2642  exit(1);
2643  }
2644  strncpy(config->rt_file[config->rt_file_count - 1], argv[argit], len);
2645  }
2646  }
2647 
2648  if (config->srid != config->out_srid && config->out_srid != SRID_UNKNOWN) {
2649  if (config->copy_statements) {
2650  rterror(_("Invalid argument combination - cannot use -Y with -s FROM_SRID:TO_SRID"));
2651  exit(1);
2652  }
2653  }
2654 
2655  /* register GDAL drivers */
2656  GDALAllRegister();
2657 
2658  /* no files provided */
2659  if (!config->rt_file_count) {
2660  rterror(_("No raster provided"));
2661  rtdealloc_config(config);
2662  exit(1);
2663  }
2664  /*
2665  at least two files, see if last is table
2666  last isn't recognized by GDAL
2667  */
2668  else if (config->rt_file_count > 1) {
2669  drv = GDALIdentifyDriver(config->rt_file[config->rt_file_count - 1], NULL);
2670 
2671  if (drv == NULL) {
2672  char *ptr;
2673  ptr = strchr(config->rt_file[config->rt_file_count - 1], '.');
2674 
2675  /* schema.table */
2676  if (ptr) {
2677  config->schema = rtalloc(sizeof(char) * (ptr - config->rt_file[config->rt_file_count - 1] + 1));
2678  if (config->schema == NULL) {
2679  rterror(_("Could not allocate memory for storing schema name"));
2680  rtdealloc_config(config);
2681  exit(1);
2682  }
2683  snprintf(config->schema, ptr - config->rt_file[config->rt_file_count - 1] + 1, "%s", config->rt_file[config->rt_file_count - 1]);
2684  config->schema[ptr - config->rt_file[config->rt_file_count - 1]] = '\0';
2685 
2686  config->table = rtalloc(sizeof(char) * (strlen(config->rt_file[config->rt_file_count - 1]) - strlen(config->schema) + 1));
2687  if (config->table == NULL) {
2688  rterror(_("Could not allocate memory for storing table name"));
2689  rtdealloc_config(config);
2690  exit(1);
2691  }
2692  snprintf(config->table, strlen(config->rt_file[config->rt_file_count - 1]) - strlen(config->schema), "%s", ptr + 1);
2693  config->table[strlen(config->rt_file[config->rt_file_count - 1]) - strlen(config->schema)] = '\0';
2694  }
2695  /* table */
2696  else {
2697  const size_t len = strlen(config->rt_file[config->rt_file_count - 1]) + 1;
2698  config->table = rtalloc(sizeof(char) * len);
2699  if (config->table == NULL) {
2700  rterror(_("Could not allocate memory for storing table name"));
2701  rtdealloc_config(config);
2702  exit(1);
2703  }
2704  strncpy(config->table, config->rt_file[config->rt_file_count - 1], len);
2705  }
2706 
2707  rtdealloc(config->rt_file[--(config->rt_file_count)]);
2708  config->rt_file = (char **) rtrealloc(config->rt_file, sizeof(char *) * config->rt_file_count);
2709  if (config->rt_file == NULL) {
2710  rterror(_("Could not reallocate the memory holding raster names"));
2711  rtdealloc_config(config);
2712  exit(1);
2713  }
2714  }
2715  }
2716 
2717  /****************************************************************************
2718  * validate raster files
2719  ****************************************************************************/
2720 
2721  /* check that GDAL recognizes all files */
2722  for (i = 0; i < config->rt_file_count; i++) {
2723  drv = GDALIdentifyDriver(config->rt_file[i], NULL);
2724 
2725  if (drv == NULL) {
2726  rterror(_("Unable to read raster file: %s"), config->rt_file[i]);
2727  rtdealloc_config(config);
2728  exit(1);
2729  }
2730  }
2731 
2732  /* process each file for just the filename */
2733  config->rt_filename = (char **) rtalloc(sizeof(char *) * config->rt_file_count);
2734  if (config->rt_filename == NULL) {
2735  rterror(_("Could not allocate memory for cleaned raster filenames"));
2736  rtdealloc_config(config);
2737  exit(1);
2738  }
2739  for (i = 0; i < config->rt_file_count; i++) {
2740  char *file;
2741  char *ptr;
2742 
2743  file = rtalloc(sizeof(char) * (strlen(config->rt_file[i]) + 1));
2744  if (file == NULL) {
2745  rterror(_("Could not allocate memory for cleaned raster filename"));
2746  rtdealloc_config(config);
2747  exit(1);
2748  }
2749  strcpy(file, config->rt_file[i]);
2750 
2751  for (ptr = file + strlen(file); ptr > file; ptr--) {
2752  if (*ptr == '/' || *ptr == '\\') {
2753  ptr++;
2754  break;
2755  }
2756  }
2757 
2758  config->rt_filename[i] = rtalloc(sizeof(char) * (strlen(ptr) + 1));
2759  if (config->rt_filename[i] == NULL) {
2760  rterror(_("Could not allocate memory for cleaned raster filename"));
2761  rtdealloc_config(config);
2762  exit(1);
2763  }
2764  strcpy(config->rt_filename[i], ptr);
2765  rtdealloc(file);
2766  }
2767 
2768  /****************************************************************************
2769  * defaults for table and column names
2770  ****************************************************************************/
2771 
2772  /* first file as proxy table name */
2773  if (config->table == NULL) {
2774  char *file;
2775  char *ptr;
2776 
2777  file = rtalloc(sizeof(char) * (strlen(config->rt_filename[0]) + 1));
2778  if (file == NULL) {
2779  rterror(_("Could not allocate memory for proxy table name"));
2780  rtdealloc_config(config);
2781  exit(1);
2782  }
2783  strcpy(file, config->rt_filename[0]);
2784 
2785  for (ptr = file + strlen(file); ptr > file; ptr--) {
2786  if (*ptr == '.') {
2787  *ptr = '\0';
2788  break;
2789  }
2790  }
2791 
2792  config->table = rtalloc(sizeof(char) * (strlen(file) + 1));
2793  if (config->table == NULL) {
2794  rterror(_("Could not allocate memory for proxy table name"));
2795  rtdealloc_config(config);
2796  exit(1);
2797  }
2798  strcpy(config->table, file);
2799  rtdealloc(file);
2800  }
2801 
2802  /* raster_column not specified, default to "rast" */
2803  if (config->raster_column == NULL) {
2804  config->raster_column = rtalloc(sizeof(char) * (strlen("rast") + 1));
2805  if (config->raster_column == NULL) {
2806  rterror(_("Could not allocate memory for default raster column name"));
2807  rtdealloc_config(config);
2808  exit(1);
2809  }
2810  strcpy(config->raster_column, "rast");
2811  }
2812 
2813  /* file_column_name not specified, default to "filename" */
2814  if (config->file_column_name == NULL) {
2815  config->file_column_name = rtalloc(sizeof(char) * (strlen("filename") + 1));
2816  if (config->file_column_name == NULL) {
2817  rterror(_("Could not allocate memory for default filename column name"));
2818  rtdealloc_config(config);
2819  exit(1);
2820  }
2821  strcpy(config->file_column_name, "filename");
2822  }
2823 
2824  /****************************************************************************
2825  * literal PostgreSQL identifiers disabled
2826  ****************************************************************************/
2827 
2828  /* no quotes, lower case everything */
2829  if (!config->quoteident) {
2830  if (config->schema != NULL)
2831  config->schema = strtolower(config->schema);
2832  if (config->table != NULL)
2833  config->table = strtolower(config->table);
2834  if (config->raster_column != NULL)
2835  config->raster_column = strtolower(config->raster_column);
2836  if (config->file_column_name != NULL)
2837  config->file_column_name = strtolower(config->file_column_name);
2838  if (config->tablespace != NULL)
2839  config->tablespace = strtolower(config->tablespace);
2840  if (config->idx_tablespace != NULL)
2841  config->idx_tablespace = strtolower(config->idx_tablespace);
2842  }
2843 
2844  /****************************************************************************
2845  * overview table names
2846  ****************************************************************************/
2847 
2848  if (config->overview_count) {
2849  char factor[4];
2850  config->overview_table = rtalloc(sizeof(char *) * config->overview_count);
2851  if (config->overview_table == NULL) {
2852  rterror(_("Could not allocate memory for overview table names"));
2853  rtdealloc_config(config);
2854  exit(1);
2855  }
2856 
2857  for (i = 0; i < config->overview_count; i++) {
2858  sprintf(factor, "%d", config->overview[i]);
2859 
2860  config->overview_table[i] = rtalloc(sizeof(char) * (strlen("o__") + strlen(factor) + strlen(config->table) + 1));
2861  if (config->overview_table[i] == NULL) {
2862  rterror(_("Could not allocate memory for overview table name"));
2863  rtdealloc_config(config);
2864  exit(1);
2865  }
2866  sprintf(config->overview_table[i], "o_%d_%s", config->overview[i], config->table);
2867  }
2868  }
2869 
2870  /****************************************************************************
2871  * check that identifiers won't get truncated
2872  ****************************************************************************/
2873 
2874  if (config->schema != NULL && strlen(config->schema) > MAXNAMELEN) {
2875  rtwarn(_("The schema name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
2876  config->schema,
2877  MAXNAMELEN
2878  );
2879  }
2880  if (config->table != NULL && strlen(config->table) > MAXNAMELEN) {
2881  rtwarn(_("The table name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
2882  config->table,
2883  MAXNAMELEN
2884  );
2885  }
2886  if (config->raster_column != NULL && strlen(config->raster_column) > MAXNAMELEN) {
2887  rtwarn(_("The column name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
2888  config->raster_column,
2889  MAXNAMELEN
2890  );
2891  }
2892  if (config->file_column_name != NULL && strlen(config->file_column_name) > MAXNAMELEN) {
2893  rtwarn(_("The column name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
2894  config->file_column_name,
2895  MAXNAMELEN
2896  );
2897  }
2898  if (config->tablespace != NULL && strlen(config->tablespace) > MAXNAMELEN) {
2899  rtwarn(_("The tablespace name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
2900  config->tablespace,
2901  MAXNAMELEN
2902  );
2903  }
2904  if (config->idx_tablespace != NULL && strlen(config->idx_tablespace) > MAXNAMELEN) {
2905  rtwarn(_("The index tablespace name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
2906  config->idx_tablespace,
2907  MAXNAMELEN
2908  );
2909  }
2910  if (config->overview_count) {
2911  for (i = 0; i < config->overview_count; i++) {
2912  if (strlen(config->overview_table[i]) > MAXNAMELEN) {
2913  rtwarn(_("The overview table name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
2914  config->overview_table[i],
2915  MAXNAMELEN
2916  );
2917  }
2918  }
2919  }
2920 
2921  /****************************************************************************
2922  * double quote identifiers
2923  ****************************************************************************/
2924 
2925  if (config->schema != NULL) {
2926  tmp = rtalloc(sizeof(char) * (strlen(config->schema) + 4));
2927  if (tmp == NULL) {
2928  rterror(_("Could not allocate memory for quoting schema name"));
2929  rtdealloc_config(config);
2930  exit(1);
2931  }
2932 
2933  sprintf(tmp, "\"%s\".", config->schema);
2934  rtdealloc(config->schema);
2935  config->schema = tmp;
2936  }
2937  if (config->table != NULL) {
2938  tmp = rtalloc(sizeof(char) * (strlen(config->table) + 3));
2939  if (tmp == NULL) {
2940  rterror(_("Could not allocate memory for quoting table name"));
2941  rtdealloc_config(config);
2942  exit(1);
2943  }
2944 
2945  sprintf(tmp, "\"%s\"", config->table);
2946  rtdealloc(config->table);
2947  config->table = tmp;
2948  }
2949  if (config->raster_column != NULL) {
2950  tmp = rtalloc(sizeof(char) * (strlen(config->raster_column) + 3));
2951  if (tmp == NULL) {
2952  rterror(_("Could not allocate memory for quoting raster column name"));
2953  rtdealloc_config(config);
2954  exit(1);
2955  }
2956 
2957  sprintf(tmp, "\"%s\"", config->raster_column);
2958  rtdealloc(config->raster_column);
2959  config->raster_column = tmp;
2960  }
2961  if (config->file_column_name != NULL) {
2962  tmp = rtalloc(sizeof(char) * (strlen(config->file_column_name) + 3));
2963  if (tmp == NULL) {
2964  rterror(_("Could not allocate memory for quoting raster column name"));
2965  rtdealloc_config(config);
2966  exit(1);
2967  }
2968 
2969  sprintf(tmp, "\"%s\"", config->file_column_name);
2970  rtdealloc(config->file_column_name);
2971  config->file_column_name = tmp;
2972  }
2973  if (config->tablespace != NULL) {
2974  tmp = rtalloc(sizeof(char) * (strlen(config->tablespace) + 3));
2975  if (tmp == NULL) {
2976  rterror(_("Could not allocate memory for quoting tablespace name"));
2977  rtdealloc_config(config);
2978  exit(1);
2979  }
2980 
2981  sprintf(tmp, "\"%s\"", config->tablespace);
2982  rtdealloc(config->tablespace);
2983  config->tablespace = tmp;
2984  }
2985  if (config->idx_tablespace != NULL) {
2986  tmp = rtalloc(sizeof(char) * (strlen(config->idx_tablespace) + 3));
2987  if (tmp == NULL) {
2988  rterror(_("Could not allocate memory for quoting index tablespace name"));
2989  rtdealloc_config(config);
2990  exit(1);
2991  }
2992 
2993  sprintf(tmp, "\"%s\"", config->idx_tablespace);
2994  rtdealloc(config->idx_tablespace);
2995  config->idx_tablespace = tmp;
2996  }
2997  if (config->overview_count) {
2998  for (i = 0; i < config->overview_count; i++) {
2999  tmp = rtalloc(sizeof(char) * (strlen(config->overview_table[i]) + 3));
3000  if (tmp == NULL) {
3001  rterror(_("Could not allocate memory for quoting overview table name"));
3002  rtdealloc_config(config);
3003  exit(1);
3004  }
3005 
3006  sprintf(tmp, "\"%s\"", config->overview_table[i]);
3007  rtdealloc(config->overview_table[i]);
3008  config->overview_table[i] = tmp;
3009  }
3010  }
3011 
3012  /****************************************************************************
3013  * processing of rasters
3014  ****************************************************************************/
3015 
3016  /* initialize string buffer */
3017  buffer = rtalloc(sizeof(STRINGBUFFER));
3018  if (buffer == NULL) {
3019  rterror(_("Could not allocate memory for output string buffer"));
3020  rtdealloc_config(config);
3021  exit(1);
3022  }
3023  init_stringbuffer(buffer);
3024 
3025  /* pass off to processing function */
3026  if (!process_rasters(config, buffer)) {
3027  rterror(_("Unable to process rasters"));
3028  rtdealloc_stringbuffer(buffer, 1);
3029  rtdealloc_config(config);
3030  exit(1);
3031  }
3032 
3033  flush_stringbuffer(buffer);
3034 
3035  rtdealloc_stringbuffer(buffer, 1);
3036  rtdealloc_config(config);
3037 
3038  return 0;
3039 }
#define FALSE
Definition: dbfopen.c:168
int main(int argc, char *argv[])
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:229
void * default_rt_allocator(size_t size)
The default memory/logging handlers installed by lwgeom_install_default_allocators()
Definition: rt_context.c:47
void rterror(const char *fmt,...)
Wrappers used for reporting errors and info.
Definition: rt_context.c:199
void * rtalloc(size_t size)
Wrappers used for managing memory.
Definition: rt_context.c:171
rt_pixtype rt_util_gdal_datatype_to_pixtype(GDALDataType gdt)
Convert GDALDataType to rt_pixtype.
Definition: rt_util.c:155
void rt_raster_set_geotransform_matrix(rt_raster raster, double *gt)
Set raster's geotransform using 6-element array.
Definition: rt_raster.c:727
void rtinfo(const char *fmt,...)
Definition: rt_context.c:211
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
int rt_raster_add_band(rt_raster raster, rt_band band, int index)
Add band data to a raster.
Definition: rt_raster.c:405
char * rt_raster_to_hexwkb(rt_raster raster, int outasin, uint32_t *hexwkbsize)
Return this raster in HEXWKB form (null-terminated hex)
Definition: rt_wkb.c:679
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
rt_pixtype
Definition: librtcore.h:185
@ PT_END
Definition: librtcore.h:197
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
Definition: rt_raster.c:48
rt_raster rt_raster_from_gdal_dataset(GDALDatasetH ds)
Return a raster from a GDAL dataset.
Definition: rt_raster.c:2177
void default_rt_deallocator(void *mem)
Definition: rt_context.c:61
void rtwarn(const char *fmt,...)
Definition: rt_context.c:224
int rt_band_check_is_nodata(rt_band band)
Returns TRUE if the band is only nodata values.
Definition: rt_band.c:1752
@ ES_NONE
Definition: librtcore.h:180
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:340
void * rtrealloc(void *mem, size_t size)
Definition: rt_context.c:179
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
rt_band rt_band_new_offline(uint16_t width, uint16_t height, rt_pixtype pixtype, uint32_t hasnodata, double nodataval, uint8_t bandNum, const char *path)
Create an out-db rt_band.
Definition: rt_band.c:124
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
Definition: rt_raster.c:363
void rtdealloc(void *mem)
Definition: rt_context.c:186
void * rt_band_get_data(rt_band band)
Get pointer to raster band data.
Definition: rt_band.c:400
int rt_band_get_ownsdata_flag(rt_band band)
Return 0 (FALSE) or non-zero (TRUE) indicating if rt_band is responsible for managing the memory for ...
Definition: rt_band.c:659
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_errorstate rt_raster_same_alignment(rt_raster rast1, rt_raster rast2, int *aligned, char **reason)
void * default_rt_reallocator(void *mem, size_t size)
Definition: rt_context.c:54
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
int rt_pixtype_size(rt_pixtype pixtype)
Return size in bytes of a value in the given pixtype.
Definition: rt_pixel.c:39
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
if(!(yy_init))
int count
Definition: genraster.py:57
band
Definition: ovdump.py:58
nband
Definition: pixval.py:53
def fmt
Definition: pixval.py:93
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
gt
Definition: window.py:78
Datum buffer(PG_FUNCTION_ARGS)
static void loader_rt_error_handler(const char *fmt, va_list ap)
Definition: raster2pgsql.c:37
static char * strreplace(const char *str, const char *oldstr, const char *newstr, int *count)
Definition: raster2pgsql.c:144
static char ** strsplit(const char *str, const char *delimiter, uint32_t *n)
Definition: raster2pgsql.c:200
static void usage()
Definition: raster2pgsql.c:330
static int array_range(int min, int max, int step, int **range, uint32_t *len)
Definition: raster2pgsql.c:96
static char * chartrim(const char *input, char *remove)
Definition: raster2pgsql.c:297
static char * trim(const char *input)
Definition: raster2pgsql.c:265
static void loader_rt_info_handler(const char *fmt, va_list ap)
Definition: raster2pgsql.c:57
static void rt_init_allocators(void)
Definition: raster2pgsql.c:67
static char * strtolower(char *str)
Definition: raster2pgsql.c:189
static void raster_destroy(rt_raster raster)
Definition: raster2pgsql.c:79
static void loader_rt_warning_handler(const char *fmt, va_list ap)
Definition: raster2pgsql.c:47
#define str(s)
Definition: raster2pgsql.c:34
#define xstr(s)
Definition: raster2pgsql.c:33
#define MAXNAMELEN
Definition: raster2pgsql.h:55
#define CSEQUAL(a, b)
Definition: raster2pgsql.h:48
#define MAXOVFACTOR
Definition: raster2pgsql.h:59
#define MINOVFACTOR
Definition: raster2pgsql.h:58
#define MAXTILESIZE
Definition: raster2pgsql.h:68
#define _(String)
Definition: shpcommon.h:24
#define POSTGIS_LIB_VERSION
Definition: sqldefines.h:13
double * nodataval
Definition: raster2pgsql.h:185
rt_pixtype * bandtype
Definition: raster2pgsql.h:180
double gt[6]
Definition: raster2pgsql.h:188
int32_t srid
Definition: raster2pgsql.h:166
uint32_t nband_count
Definition: raster2pgsql.h:176
GDALDataType * gdalbandtype
Definition: raster2pgsql.h:179
int tile_size[2]
Definition: raster2pgsql.h:191
uint32_t dim[2]
Definition: raster2pgsql.h:172
uint32_t length
Definition: raster2pgsql.h:196