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