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