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