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