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