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