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