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