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