postgis/raster/loader/raster2pgsql.c
Bborie Park e3bc47bfe9 revert option for -s. Ticket #2891
git-svn-id: http://svn.osgeo.org/postgis/trunk@12882 b70326c6-7e19-0410-871a-916f4a2858ee
2014-08-11 03:23:05 +00:00

3044 lines
81 KiB
C

/*
* $Id$
*
* PostGIS raster loader
* http://trac.osgeo.org/postgis/wiki/WKTRaster
*
* Copyright 2001-2003 Refractions Research Inc.
* Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
* Copyright 2009 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
* Copyright (C) 2011 Regents of the University of California
* <bkpark@ucdavis.edu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "raster2pgsql.h"
#include "gdal_vrt.h"
#include "ogr_srs_api.h"
#include <assert.h>
static void
loader_rt_error_handler(const char *fmt, va_list ap) {
static const char *label = "ERROR: ";
char newfmt[1024] = {0};
snprintf(newfmt, 1024, "%s%s\n", label, fmt);
newfmt[1023] = '\0';
vfprintf(stderr, newfmt, ap);
va_end(ap);
}
static void
loader_rt_warning_handler(const char *fmt, va_list ap) {
static const char *label = "WARNING: ";
char newfmt[1024] = {0};
snprintf(newfmt, 1024, "%s%s\n", label, fmt);
newfmt[1023] = '\0';
vfprintf(stderr, newfmt, ap);
va_end(ap);
}
static void
loader_rt_info_handler(const char *fmt, va_list ap) {
static const char *label = "INFO: ";
char newfmt[1024] = {0};
snprintf(newfmt, 1024, "%s%s\n", label, fmt);
newfmt[1023] = '\0';
vfprintf(stderr, newfmt, ap);
va_end(ap);
}
void rt_init_allocators(void) {
rt_set_handlers(
default_rt_allocator,
default_rt_reallocator,
default_rt_deallocator,
loader_rt_error_handler,
loader_rt_info_handler,
loader_rt_warning_handler
);
}
static void
raster_destroy(rt_raster raster) {
uint16_t i;
uint16_t nbands = rt_raster_get_num_bands(raster);
for (i = 0; i < nbands; i++) {
rt_band band = rt_raster_get_band(raster, i);
if (band == NULL) continue;
if (!rt_band_is_offline(band) && !rt_band_get_ownsdata_flag(band)) {
void* mem = rt_band_get_data(band);
if (mem) rtdealloc(mem);
}
rt_band_destroy(band);
}
rt_raster_destroy(raster);
}
static int
array_range(int min, int max, int step, int **range, int *len) {
int i = 0;
int j = 0;
step = abs(step);
*len = (abs(max - min) + 1 + (step / 2)) / step;
*range = rtalloc(sizeof(int) * *len);
if (min < max) {
for (i = min, j = 0; i <= max; i += step, j++)
(*range)[j] = i;
}
else if (max < min) {
if (step > 0) step *= -1;
for (i = min, j = 0; i >= max; i += step, j++)
(*range)[j] = i;
}
else if (min == max) {
(*range)[0] = min;
}
else {
*len = 0;
*range = NULL;
return 0;
}
return 1;
}
/* string replacement function taken from
* http://ubuntuforums.org/showthread.php?s=aa6f015109fd7e4c7e30d2fd8b717497&t=141670&page=3
*/
/* ---------------------------------------------------------------------------
Name : replace - Search & replace a substring by another one.
Creation : Thierry Husson, Sept 2010
Parameters :
str : Big string where we search
oldstr : Substring we are looking for
newstr : Substring we want to replace with
count : Optional pointer to int (input / output value). NULL to ignore.
Input: Maximum replacements to be done. NULL or < 1 to do all.
Output: Number of replacements done or -1 if not enough memory.
Returns : Pointer to the new string or NULL if error.
Notes :
- Case sensitive - Otherwise, replace functions "strstr" by "strcasestr"
- Always allocates memory for the result.
--------------------------------------------------------------------------- */
static char*
strreplace(
const char *str,
const char *oldstr, const char *newstr,
int *count
) {
const char *tmp = str;
char *result;
int found = 0;
int length, reslen;
int oldlen = strlen(oldstr);
int newlen = strlen(newstr);
int limit = (count != NULL && *count > 0) ? *count : -1;
tmp = str;
while ((tmp = strstr(tmp, oldstr)) != NULL && found != limit)
found++, tmp += oldlen;
length = strlen(str) + found * (newlen - oldlen);
if ((result = (char *) rtalloc(length + 1)) == NULL) {
rterror(_("strreplace: Not enough memory"));
found = -1;
}
else {
tmp = str;
limit = found; /* Countdown */
reslen = 0; /* length of current result */
/* Replace each old string found with new string */
while ((limit-- > 0) && (tmp = strstr(tmp, oldstr)) != NULL) {
length = (tmp - str); /* Number of chars to keep intouched */
strncpy(result + reslen, str, length); /* Original part keeped */
strcpy(result + (reslen += length), newstr); /* Insert new string */
reslen += newlen;
tmp += oldlen;
str = tmp;
}
strcpy(result + reslen, str); /* Copies last part and ending null char */
}
if (count != NULL) *count = found;
return result;
}
static char *
strtolower(char * str) {
int j;
for (j = strlen(str) - 1; j >= 0; j--)
str[j] = tolower(str[j]);
return str;
}
/* split a string based on a delimiter */
static char**
strsplit(const char *str, const char *delimiter, int *n) {
char *tmp = NULL;
char **rtn = NULL;
char *token = NULL;
*n = 0;
if (!str)
return NULL;
/* copy str to tmp as strtok will mangle the string */
tmp = rtalloc(sizeof(char) * (strlen(str) + 1));
if (NULL == tmp) {
rterror(_("strsplit: Not enough memory"));
return NULL;
}
strcpy(tmp, str);
if (!strlen(tmp) || !delimiter || !strlen(delimiter)) {
*n = 1;
rtn = (char **) rtalloc(*n * sizeof(char *));
if (NULL == rtn) {
rterror(_("strsplit: Not enough memory"));
return NULL;
}
rtn[0] = (char *) rtalloc(sizeof(char) * (strlen(tmp) + 1));
if (NULL == rtn[0]) {
rterror(_("strsplit: Not enough memory"));
return NULL;
}
strcpy(rtn[0], tmp);
rtdealloc(tmp);
return rtn;
}
token = strtok(tmp, delimiter);
while (token != NULL) {
if (*n < 1) {
rtn = (char **) rtalloc(sizeof(char *));
}
else {
rtn = (char **) rtrealloc(rtn, (*n + 1) * sizeof(char *));
}
if (NULL == rtn) {
rterror(_("strsplit: Not enough memory"));
return NULL;
}
rtn[*n] = NULL;
rtn[*n] = (char *) rtalloc(sizeof(char) * (strlen(token) + 1));
if (NULL == rtn[*n]) {
rterror(_("strsplit: Not enough memory"));
return NULL;
}
strcpy(rtn[*n], token);
*n = *n + 1;
token = strtok(NULL, delimiter);
}
rtdealloc(tmp);
return rtn;
}
static char*
trim(const char *input) {
char *rtn;
char *ptr;
uint32_t offset = 0;
if (!input)
return NULL;
else if (!*input)
return (char *) input;
/* trim left */
while (isspace(*input))
input++;
/* trim right */
ptr = ((char *) input) + strlen(input);
while (isspace(*--ptr))
offset++;
rtn = rtalloc(sizeof(char) * (strlen(input) - offset + 1));
if (NULL == rtn) {
rterror(_("trim: Not enough memory"));
return NULL;
}
strncpy(rtn, input, strlen(input) - offset);
rtn[strlen(input) - offset] = '\0';
return rtn;
}
static char*
chartrim(const char *input, char *remove) {
char *rtn = NULL;
char *ptr = NULL;
uint32_t offset = 0;
if (!input)
return NULL;
else if (!*input)
return (char *) input;
/* trim left */
while (strchr(remove, *input) != NULL)
input++;
/* trim right */
ptr = ((char *) input) + strlen(input);
while (strchr(remove, *--ptr) != NULL)
offset++;
rtn = rtalloc(sizeof(char) * (strlen(input) - offset + 1));
if (NULL == rtn) {
rterror(_("chartrim: Not enough memory"));
return NULL;
}
strncpy(rtn, input, strlen(input) - offset);
rtn[strlen(input) - offset] = '\0';
return rtn;
}
static void
usage() {
printf(_("RELEASE: %s GDAL_VERSION=%d (r%d)\n"), POSTGIS_LIB_VERSION, POSTGIS_GDAL_VERSION, POSTGIS_SVN_REVISION);
printf(_(
"USAGE: raster2pgsql [<options>] <raster>[ <raster>[ ...]] [[<schema>.]<table>]\n"
" Multiple rasters can also be specified using wildcards (*,?).\n"
"\n"
"OPTIONS:\n"
));
/*
printf(_(
" -s [<from>:]<srid> Set the SRID field. Defaults to %d.\n"
" Optionally reprojects from given SRID (cannot be used with -Y).\n"
" Raster's metadata will be checked to determine an appropriate SRID.\n"
" If a srid of %d is provided (either as from or as target).\n"
), SRID_UNKNOWN, SRID_UNKNOWN);
*/
printf(_(
" -s <srid> Set the SRID field. Defaults to %d. If SRID not\n"
" provided or is %d, raster's metadata will be checked to\n"
" determine an appropriate SRID.\n"
), SRID_UNKNOWN, SRID_UNKNOWN);
printf(_(
" -b <band> Index (1-based) of band to extract from raster. For more\n"
" than one band index, separate with comma (,). Ranges can be\n"
" defined by separating with dash (-). If unspecified, all bands\n"
" of raster will be extracted.\n"
));
printf(_(
" -t <tile size> Cut raster into tiles to be inserted one per\n"
" table row. <tile size> is expressed as WIDTHxHEIGHT.\n"
" <tile size> can also be \"auto\" to allow the loader to compute\n"
" an appropriate tile size using the first raster and applied to\n"
" all rasters.\n"
));
printf(_(
" -P Pad right-most and bottom-most tiles to guarantee that all tiles\n"
" have the same width and height.\n"
));
printf(_(
" -R Register the raster as an out-of-db (filesystem) raster. Provided\n"
" raster should have absolute path to the file\n"
));
printf(_(
" (-d|a|c|p) These are mutually exclusive options:\n"
" -d Drops the table, then recreates it and populates\n"
" it with current raster data.\n"
" -a Appends raster into current table, must be\n"
" exactly the same table schema.\n"
" -c Creates a new table and populates it, this is the\n"
" default if you do not specify any options.\n"
" -p Prepare mode, only creates the table.\n"
));
printf(_(
" -f <column> Specify the name of the raster column\n"
));
printf(_(
" -F Add a column with the filename of the raster.\n"
));
printf(_(
" -n <column> Specify the name of the filename column. Implies -F.\n"
));
printf(_(
" -l <overview factor> Create overview of the raster. For more than\n"
" one factor, separate with comma(,). Overview table name follows\n"
" the pattern o_<overview factor>_<table>. Created overview is\n"
" stored in the database and is not affected by -R.\n"
));
printf(_(
" -q Wrap PostgreSQL identifiers in quotes.\n"
));
printf(_(
" -I Create a GIST spatial index on the raster column. The ANALYZE\n"
" command will automatically be issued for the created index.\n"
));
printf(_(
" -M Run VACUUM ANALYZE on the table of the raster column. Most\n"
" useful when appending raster to existing table with -a.\n"
));
printf(_(
" -C Set the standard set of constraints on the raster\n"
" column after the rasters are loaded. Some constraints may fail\n"
" if one or more rasters violate the constraint.\n"
" -x Disable setting the max extent constraint. Only applied if\n"
" -C flag is also used.\n"
" -r Set the constraints (spatially unique and coverage tile) for\n"
" regular blocking. Only applied if -C flag is also used.\n"
));
printf(_(
" -T <tablespace> Specify the tablespace for the new table.\n"
" Note that indices (including the primary key) will still use\n"
" the default tablespace unless the -X flag is also used.\n"
));
printf(_(
" -X <tablespace> Specify the tablespace for the table's new index.\n"
" This applies to the primary key and the spatial index if\n"
" the -I flag is used.\n"
));
printf(_(
" -N <nodata> NODATA value to use on bands without a NODATA value.\n"
));
printf(_(
" -k Skip NODATA value checks for each raster band.\n"
));
printf(_(
" -E <endian> Control endianness of generated binary output of\n"
" raster. Use 0 for XDR and 1 for NDR (default). Only NDR\n"
" is supported at this time.\n"
));
printf(_(
" -V <version> Specify version of output WKB format. Default\n"
" is 0. Only 0 is supported at this time.\n"
));
printf(_(
" -e Execute each statement individually, do not use a transaction.\n"
));
printf(_(
" -Y Use COPY statements instead of INSERT statements.\n"
));
printf(_(
" -G Print the supported GDAL raster formats.\n"
));
printf(_(
" -? Display this help screen.\n"
));
}
static void calc_tile_size(
int dimX, int dimY,
int *tileX, int *tileY
) {
int i = 0;
int j = 0;
int min = 30;
int max = 100;
int d = 0;
double r = 0;
/*int _d = 0;*/
double _r = -1;
int _i = 0;
/* j = 0, X */
for (j = 0; j < 2; j++) {
_i = 0;
/*_d = 0;*/
_r = -1;
if (j < 1 && dimX <= max) {
*tileX = dimX;
continue;
}
else if (dimY <= max) {
*tileY = dimY;
continue;
}
for (i = max; i >= min; i--) {
if (j < 1) {
d = dimX / i;
r = (double) dimX / (double) i;
}
else {
d = dimY / i;
r = (double) dimY / (double) i;
}
r = r - (double) d;
if (
FLT_EQ(_r, -1) ||
(r < _r) ||
FLT_EQ(r, _r)
) {
/*_d = d;*/
_r = r;
_i = i;
}
}
if (j < 1)
*tileX = _i;
else
*tileY = _i;
}
}
static void
init_rastinfo(RASTERINFO *info) {
info->srid = SRID_UNKNOWN;
info->srs = NULL;
memset(info->dim, 0, sizeof(double) * 2);
info->nband_count = 0;
info->nband = NULL;
info->gdalbandtype = NULL;
info->bandtype = NULL;
info->hasnodata = NULL;
info->nodataval = NULL;
memset(info->gt, 0, sizeof(double) * 6);
memset(info->tile_size, 0, sizeof(int) * 2);
}
static void
rtdealloc_rastinfo(RASTERINFO *info) {
if (info->srs != NULL)
rtdealloc(info->srs);
if (info->nband_count > 0 && info->nband != NULL)
rtdealloc(info->nband);
if (info->gdalbandtype != NULL)
rtdealloc(info->gdalbandtype);
if (info->bandtype != NULL)
rtdealloc(info->bandtype);
if (info->hasnodata != NULL)
rtdealloc(info->hasnodata);
if (info->nodataval != NULL)
rtdealloc(info->nodataval);
}
static int
copy_rastinfo(RASTERINFO *dst, RASTERINFO *src) {
if (src->srs != NULL) {
dst->srs = rtalloc(sizeof(char) * (strlen(src->srs) + 1));
if (dst->srs == NULL) {
rterror(_("copy_rastinfo: Not enough memory"));
return 0;
}
strcpy(dst->srs, src->srs);
}
memcpy(dst->dim, src->dim, sizeof(uint32_t) * 2);
dst->nband_count = src->nband_count;
if (src->nband_count && src->nband != NULL) {
dst->nband = rtalloc(sizeof(int) * src->nband_count);
if (dst->nband == NULL) {
rterror(_("copy_rastinfo: Not enough memory"));
return 0;
}
memcpy(dst->nband, src->nband, sizeof(int) * src->nband_count);
}
if (src->gdalbandtype != NULL) {
dst->gdalbandtype = rtalloc(sizeof(GDALDataType) * src->nband_count);
if (dst->gdalbandtype == NULL) {
rterror(_("copy_rastinfo: Not enough memory"));
return 0;
}
memcpy(dst->gdalbandtype, src->gdalbandtype, sizeof(GDALDataType) * src->nband_count);
}
if (src->bandtype != NULL) {
dst->bandtype = rtalloc(sizeof(rt_pixtype) * src->nband_count);
if (dst->bandtype == NULL) {
rterror(_("copy_rastinfo: Not enough memory"));
return 0;
}
memcpy(dst->bandtype, src->bandtype, sizeof(rt_pixtype) * src->nband_count);
}
if (src->hasnodata != NULL) {
dst->hasnodata = rtalloc(sizeof(int) * src->nband_count);
if (dst->hasnodata == NULL) {
rterror(_("copy_rastinfo: Not enough memory"));
return 0;
}
memcpy(dst->hasnodata, src->hasnodata, sizeof(int) * src->nband_count);
}
if (src->nodataval != NULL) {
dst->nodataval = rtalloc(sizeof(double) * src->nband_count);
if (dst->nodataval == NULL) {
rterror(_("copy_rastinfo: Not enough memory"));
return 0;
}
memcpy(dst->nodataval, src->nodataval, sizeof(double) * src->nband_count);
}
memcpy(dst->gt, src->gt, sizeof(double) * 6);
memcpy(dst->tile_size, src->tile_size, sizeof(int) * 2);
return 1;
}
static void
diff_rastinfo(RASTERINFO *x, RASTERINFO *ref) {
static uint8_t msg[6] = {0};
int i = 0;
/* # of bands */
if (
!msg[0] &&
x->nband_count != ref->nband_count
) {
rtwarn(_("Different number of bands found in the set of rasters being converted to PostGIS raster"));
msg[0]++;
}
/* pixel types */
if (!msg[1]) {
for (i = 0; i < ref->nband_count; i++) {
if (x->bandtype[i] != ref->bandtype[i]) {
rtwarn(_("Different pixel types found for band %d in the set of rasters being converted to PostGIS raster"), ref->nband[i]);
msg[1]++;
}
}
}
/* hasnodata */
if (!msg[2]) {
for (i = 0; i < ref->nband_count; i++) {
if (x->hasnodata[i] != ref->hasnodata[i]) {
rtwarn(_("Different hasnodata flags found for band %d in the set of rasters being converted to PostGIS raster"), ref->nband[i]);
msg[2]++;
}
}
}
/* nodataval */
if (!msg[3]) {
for (i = 0; i < ref->nband_count; i++) {
if (!x->hasnodata[i] && !ref->hasnodata[i]) continue;
if (FLT_NEQ(x->hasnodata[i], ref->hasnodata[i])) {
rtwarn(_("Different NODATA values found for band %d in the set of rasters being converted to PostGIS raster"), ref->nband[i]);
msg[3]++;
}
}
}
/* alignment */
if (!msg[4]) {
rt_raster rx = NULL;
rt_raster rref = NULL;
int err;
int aligned;
if (
(rx = rt_raster_new(1, 1)) == NULL ||
(rref = rt_raster_new(1, 1)) == NULL
) {
rterror(_("diff_rastinfo: Could not allocate memory for raster alignment test"));
if (rx != NULL) rt_raster_destroy(rx);
if (rref != NULL) rt_raster_destroy(rref);
return;
}
rt_raster_set_geotransform_matrix(rx, x->gt);
rt_raster_set_geotransform_matrix(rref, ref->gt);
err = rt_raster_same_alignment(rx, rref, &aligned, NULL);
rt_raster_destroy(rx);
rt_raster_destroy(rref);
if (err != ES_NONE) {
rterror(_("diff_rastinfo: Could not run raster alignment test"));
return;
}
if (!aligned) {
rtwarn(_("Raster with different alignment found in the set of rasters being converted to PostGIS raster"));
msg[4]++;
}
}
/* tile size */
if (!msg[5]) {
for (i = 0; i < 2; i++) {
if (FLT_NEQ(x->tile_size[i], ref->tile_size[i])) {
rtwarn(_("Different tile sizes found in the set of rasters being converted to PostGIS raster"));
msg[5]++;
break;
}
}
}
}
static void
init_config(RTLOADERCFG *config) {
config->rt_file_count = 0;
config->rt_file = NULL;
config->rt_filename = NULL;
config->schema = NULL;
config->table = NULL;
config->raster_column = NULL;
config->file_column = 0;
config->file_column_name = NULL;
config->overview_count = 0;
config->overview = NULL;
config->overview_table = NULL;
config->quoteident = 0;
config->srid = config->out_srid = SRID_UNKNOWN;
config->nband = NULL;
config->nband_count = 0;
memset(config->tile_size, 0, sizeof(int) * 2);
config->pad_tile = 0;
config->outdb = 0;
config->opt = 'c';
config->idx = 0;
config->maintenance = 0;
config->constraints = 0;
config->max_extent = 1;
config->regular_blocking = 0;
config->tablespace = NULL;
config->idx_tablespace = NULL;
config->hasnodata = 0;
config->nodataval = 0;
config->skip_nodataval_check = 0;
config->endian = 1;
config->version = 0;
config->transaction = 1;
config->copy_statements = 0;
}
static void
rtdealloc_config(RTLOADERCFG *config) {
int i = 0;
if (config->rt_file_count) {
for (i = config->rt_file_count - 1; i >= 0; i--) {
rtdealloc(config->rt_file[i]);
if (config->rt_filename)
rtdealloc(config->rt_filename[i]);
}
rtdealloc(config->rt_file);
if (config->rt_filename)
rtdealloc(config->rt_filename);
}
if (config->schema != NULL)
rtdealloc(config->schema);
if (config->table != NULL)
rtdealloc(config->table);
if (config->raster_column != NULL)
rtdealloc(config->raster_column);
if (config->file_column_name != NULL)
rtdealloc(config->file_column_name);
if (config->overview_count > 0) {
if (config->overview != NULL)
rtdealloc(config->overview);
if (config->overview_table != NULL) {
for (i = config->overview_count - 1; i >= 0; i--)
rtdealloc(config->overview_table[i]);
rtdealloc(config->overview_table);
}
}
if (config->nband_count > 0 && config->nband != NULL)
rtdealloc(config->nband);
if (config->tablespace != NULL)
rtdealloc(config->tablespace);
if (config->idx_tablespace != NULL)
rtdealloc(config->idx_tablespace);
rtdealloc(config);
}
static void
init_stringbuffer(STRINGBUFFER *buffer) {
buffer->line = NULL;
buffer->length = 0;
}
static void
rtdealloc_stringbuffer(STRINGBUFFER *buffer, int freebuffer) {
if (buffer->length) {
uint32_t i = 0;
for (i = 0; i < buffer->length; i++) {
if (buffer->line[i] != NULL)
rtdealloc(buffer->line[i]);
}
rtdealloc(buffer->line);
}
buffer->line = NULL;
buffer->length = 0;
if (freebuffer)
rtdealloc(buffer);
}
static void
dump_stringbuffer(STRINGBUFFER *buffer) {
int i = 0;
for (i = 0; i < buffer->length; i++) {
printf("%s\n", buffer->line[i]);
}
}
static void
flush_stringbuffer(STRINGBUFFER *buffer) {
dump_stringbuffer(buffer);
rtdealloc_stringbuffer(buffer, 0);
}
/* Takes ownership of the passed string */
static int
append_stringbuffer(STRINGBUFFER *buffer, const char *str) {
buffer->length++;
buffer->line = rtrealloc(buffer->line, sizeof(char *) * buffer->length);
if (buffer->line == NULL) {
rterror(_("append_stringbuffer: Could not allocate memory for appending string to buffer"));
return 0;
}
buffer->line[buffer->length - 1] = (char *) str;
return 1;
}
static int
append_sql_to_buffer(STRINGBUFFER *buffer, const char *str) {
if (buffer->length > 9)
flush_stringbuffer(buffer);
return append_stringbuffer(buffer, str);
}
static int
copy_from(const char *schema, const char *table, const char *column,
const char *filename, const char *file_column_name,
STRINGBUFFER *buffer)
{
char *sql = NULL;
uint32_t len = 0;
assert(table != NULL);
assert(column != NULL);
len = strlen("COPY () FROM stdin;") + 1;
if (schema != NULL)
len += strlen(schema);
len += strlen(table);
len += strlen(column);
if (filename != NULL)
len += strlen(",") + strlen(file_column_name);
sql = rtalloc(sizeof(char) * len);
if (sql == NULL) {
rterror(_("copy_from: Could not allocate memory for COPY statement"));
return 0;
}
sprintf(sql, "COPY %s%s (%s%s%s) FROM stdin;",
(schema != NULL ? schema : ""),
table,
column,
(filename != NULL ? "," : ""),
(filename != NULL ? file_column_name : "")
);
append_sql_to_buffer(buffer, sql);
sql = NULL;
return 1;
}
static int
copy_from_end(STRINGBUFFER *buffer)
{
/* end of data */
append_sql_to_buffer(buffer, strdup("\\."));
return 1;
}
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
) {
char *fn = NULL;
uint32_t len = 0;
char *sql = NULL;
uint32_t x = 0;
assert(table != NULL);
assert(column != NULL);
/* COPY statements */
if (copy_statements) {
if (!copy_from(
schema, table, column,
(file_column_name ? filename : NULL), file_column_name,
buffer
)) {
rterror(_("insert_records: Could not add COPY statement to string buffer"));
return 0;
}
/* escape tabs in filename */
if (filename != NULL)
fn = strreplace(filename, "\t", "\\t", NULL);
/* rows */
for (x = 0; x < tileset->length; x++) {
len = strlen(tileset->line[x]) + 1;
if (filename != NULL)
len += strlen(fn) + 1;
sql = rtalloc(sizeof(char) * len);
if (sql == NULL) {
rterror(_("insert_records: Could not allocate memory for COPY statement"));
return 0;
}
sprintf(sql, "%s%s%s",
tileset->line[x],
(filename != NULL ? "\t" : ""),
(filename != NULL ? fn : "")
);
append_sql_to_buffer(buffer, sql);
sql = NULL;
}
if (!copy_from_end(buffer)) {
rterror(_("process_rasters: Could not add COPY end statement to string buffer"));
return 0;
}
}
/* INSERT statements */
else {
len = strlen("INSERT INTO () VALUES (ST_Transform(''::raster,xxxxxxxxx));") + 1;
if (schema != NULL)
len += strlen(schema);
len += strlen(table);
len += strlen(column);
if (filename != NULL)
len += strlen(",") + strlen(file_column_name);
/* escape single-quotes in filename */
if (filename != NULL)
fn = strreplace(filename, "'", "''", NULL);
for (x = 0; x < tileset->length; x++) {
char *ptr;
int sqllen = len;
sqllen += strlen(tileset->line[x]);
if (filename != NULL)
sqllen += strlen(",''") + strlen(fn);
sql = rtalloc(sizeof(char) * sqllen);
if (sql == NULL) {
rterror(_("insert_records: Could not allocate memory for INSERT statement"));
return 0;
}
ptr = sql;
ptr += sprintf(sql, "INSERT INTO %s%s (%s%s%s) VALUES (",
(schema != NULL ? schema : ""),
table,
column,
(filename != NULL ? "," : ""),
(filename != NULL ? file_column_name : "")
);
if (out_srid != SRID_UNKNOWN) {
ptr += sprintf(ptr, "ST_Transform(");
}
ptr += sprintf(ptr, "'%s'::raster",
tileset->line[x]
);
if (out_srid != SRID_UNKNOWN) {
ptr += sprintf(ptr, ", %d)", out_srid);
}
if (filename != NULL) {
ptr += sprintf(ptr, ",'%s'", fn);
}
ptr += sprintf(ptr, ");");
append_sql_to_buffer(buffer, sql);
sql = NULL;
}
}
if (fn != NULL) rtdealloc(fn);
return 1;
}
static int
drop_table(const char *schema, const char *table, STRINGBUFFER *buffer) {
char *sql = NULL;
uint32_t len = 0;
len = strlen("DROP TABLE IF EXISTS ;") + 1;
if (schema != NULL)
len += strlen(schema);
len += strlen(table);
sql = rtalloc(sizeof(char) * len);
if (sql == NULL) {
rterror(_("drop_table: Could not allocate memory for DROP TABLE statement"));
return 0;
}
sprintf(sql, "DROP TABLE IF EXISTS %s%s;",
(schema != NULL ? schema : ""),
table
);
append_sql_to_buffer(buffer, sql);
return 1;
}
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
) {
char *sql = NULL;
uint32_t len = 0;
assert(table != NULL);
assert(column != NULL);
len = strlen("CREATE TABLE (\"rid\" serial PRIMARY KEY, raster);") + 1;
if (schema != NULL)
len += strlen(schema);
len += strlen(table);
len += strlen(column);
if (file_column)
len += strlen(", text") + strlen(file_column_name);
if (tablespace != NULL)
len += strlen(" TABLESPACE ") + strlen(tablespace);
if (idx_tablespace != NULL)
len += strlen(" USING INDEX TABLESPACE ") + strlen(idx_tablespace);
sql = rtalloc(sizeof(char) * len);
if (sql == NULL) {
rterror(_("create_table: Could not allocate memory for CREATE TABLE statement"));
return 0;
}
sprintf(sql, "CREATE TABLE %s%s (\"rid\" serial PRIMARY KEY%s%s,%s raster%s%s%s)%s%s;",
(schema != NULL ? schema : ""),
table,
(idx_tablespace != NULL ? " USING INDEX TABLESPACE " : ""),
(idx_tablespace != NULL ? idx_tablespace : ""),
column,
(file_column ? "," : ""),
(file_column ? file_column_name : ""),
(file_column ? " text" : ""),
(tablespace != NULL ? " TABLESPACE " : ""),
(tablespace != NULL ? tablespace : "")
);
append_sql_to_buffer(buffer, sql);
return 1;
}
static int
create_index(
const char *schema, const char *table, const char *column,
const char *tablespace,
STRINGBUFFER *buffer
) {
char *sql = NULL;
uint32_t len = 0;
char *_table = NULL;
char *_column = NULL;
assert(table != NULL);
assert(column != NULL);
_table = chartrim(table, "\"");
_column = chartrim(column, "\"");
/* create index */
len = strlen("CREATE INDEX \"__gist\" ON USING gist (st_convexhull());") + 1;
if (schema != NULL)
len += strlen(schema);
len += strlen(_table);
len += strlen(_column);
len += strlen(table);
len += strlen(column);
if (tablespace != NULL)
len += strlen(" TABLESPACE ") + strlen(tablespace);
sql = rtalloc(sizeof(char) * len);
if (sql == NULL) {
rterror(_("create_index: Could not allocate memory for CREATE INDEX statement"));
rtdealloc(_table);
rtdealloc(_column);
return 0;
}
sprintf(sql, "CREATE INDEX ON %s%s USING gist (st_convexhull(%s))%s%s;",
(schema != NULL ? schema : ""),
table,
column,
(tablespace != NULL ? " TABLESPACE " : ""),
(tablespace != NULL ? tablespace : "")
);
rtdealloc(_table);
rtdealloc(_column);
append_sql_to_buffer(buffer, sql);
return 1;
}
static int
analyze_table(
const char *schema, const char *table,
STRINGBUFFER *buffer
) {
char *sql = NULL;
uint32_t len = 0;
assert(table != NULL);
len = strlen("ANALYZE ;") + 1;
if (schema != NULL)
len += strlen(schema);
len += strlen(table);
sql = rtalloc(sizeof(char) * len);
if (sql == NULL) {
rterror(_("analyze_table: Could not allocate memory for ANALYZE TABLE statement"));
return 0;
}
sprintf(sql, "ANALYZE %s%s;",
(schema != NULL ? schema : ""),
table
);
append_sql_to_buffer(buffer, sql);
return 1;
}
static int
vacuum_table(
const char *schema, const char *table,
STRINGBUFFER *buffer
) {
char *sql = NULL;
uint32_t len = 0;
assert(table != NULL);
len = strlen("VACUUM ANALYZE ;") + 1;
if (schema != NULL)
len += strlen(schema);
len += strlen(table);
sql = rtalloc(sizeof(char) * len);
if (sql == NULL) {
rterror(_("vacuum_table: Could not allocate memory for VACUUM statement"));
return 0;
}
sprintf(sql, "VACUUM ANALYZE %s%s;",
(schema != NULL ? schema : ""),
table
);
append_sql_to_buffer(buffer, sql);
return 1;
}
static int
add_raster_constraints(
const char *schema, const char *table, const char *column,
int regular_blocking, int max_extent,
STRINGBUFFER *buffer
) {
char *sql = NULL;
uint32_t len = 0;
char *_tmp = NULL;
char *_schema = NULL;
char *_table = NULL;
char *_column = NULL;
assert(table != NULL);
assert(column != NULL);
/* schema */
if (schema != NULL) {
_tmp = chartrim(schema, ".");
_schema = chartrim(_tmp, "\"");
rtdealloc(_tmp);
_tmp = strreplace(_schema, "'", "''", NULL);
rtdealloc(_schema);
_schema = _tmp;
}
/* table */
_tmp = chartrim(table, "\"");
_table = strreplace(_tmp, "'", "''", NULL);
rtdealloc(_tmp);
/* column */
_tmp = chartrim(column, "\"");
_column = strreplace(_tmp, "'", "''", NULL);
rtdealloc(_tmp);
len = strlen("SELECT AddRasterConstraints('','','',TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE,TRUE,TRUE,FALSE);") + 1;
if (_schema != NULL)
len += strlen(_schema);
len += strlen(_table);
len += strlen(_column);
sql = rtalloc(sizeof(char) * len);
if (sql == NULL) {
rterror(_("add_raster_constraints: Could not allocate memory for AddRasterConstraints statement"));
return 0;
}
sprintf(sql, "SELECT AddRasterConstraints('%s','%s','%s',TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,%s,TRUE,TRUE,TRUE,TRUE,%s);",
(_schema != NULL ? _schema : ""),
_table,
_column,
(regular_blocking ? "TRUE" : "FALSE"),
(max_extent ? "TRUE" : "FALSE")
);
if (_schema != NULL)
rtdealloc(_schema);
rtdealloc(_table);
rtdealloc(_column);
append_sql_to_buffer(buffer, sql);
return 1;
}
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
) {
char *sql = NULL;
uint32_t len = 0;
char *_tmp = NULL;
char *_ovschema = NULL;
char *_ovtable = NULL;
char *_ovcolumn = NULL;
char *_schema = NULL;
char *_table = NULL;
char *_column = NULL;
assert(ovtable != NULL);
assert(ovcolumn != NULL);
assert(table != NULL);
assert(column != NULL);
assert(factor >= MINOVFACTOR && factor <= MAXOVFACTOR);
/* overview schema */
if (ovschema != NULL) {
_tmp = chartrim(ovschema, ".");
_ovschema = chartrim(_tmp, "\"");
rtdealloc(_tmp);
_tmp = strreplace(_ovschema, "'", "''", NULL);
rtdealloc(_ovschema);
_ovschema = _tmp;
}
/* overview table */
_tmp = chartrim(ovtable, "\"");
_ovtable = strreplace(_tmp, "'", "''", NULL);
rtdealloc(_tmp);
/* overview column*/
_tmp = chartrim(ovcolumn, "\"");
_ovcolumn = strreplace(_tmp, "'", "''", NULL);
rtdealloc(_tmp);
/* schema */
if (schema != NULL) {
_tmp = chartrim(schema, ".");
_schema = chartrim(_tmp, "\"");
rtdealloc(_tmp);
_tmp = strreplace(_schema, "'", "''", NULL);
rtdealloc(_schema);
_schema = _tmp;
}
/* table */
_tmp = chartrim(table, "\"");
_table = strreplace(_tmp, "'", "''", NULL);
rtdealloc(_tmp);
/* column */
_tmp = chartrim(column, "\"");
_column = strreplace(_tmp, "'", "''", NULL);
rtdealloc(_tmp);
len = strlen("SELECT AddOverviewConstraints('','','','','','',);") + 5;
if (_ovschema != NULL)
len += strlen(_ovschema);
len += strlen(_ovtable);
len += strlen(_ovcolumn);
if (_schema != NULL)
len += strlen(_schema);
len += strlen(_table);
len += strlen(_column);
sql = rtalloc(sizeof(char) * len);
if (sql == NULL) {
rterror(_("add_overview_constraints: Could not allocate memory for AddOverviewConstraints statement"));
return 0;
}
sprintf(sql, "SELECT AddOverviewConstraints('%s','%s','%s','%s','%s','%s',%d);",
(_ovschema != NULL ? _ovschema : ""),
_ovtable,
_ovcolumn,
(_schema != NULL ? _schema : ""),
_table,
_column,
factor
);
if (_ovschema != NULL)
rtdealloc(_ovschema);
rtdealloc(_ovtable);
rtdealloc(_ovcolumn);
if (_schema != NULL)
rtdealloc(_schema);
rtdealloc(_table);
rtdealloc(_column);
append_sql_to_buffer(buffer, sql);
return 1;
}
static int
build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, int ovx, STRINGBUFFER *tileset, STRINGBUFFER *buffer) {
GDALDatasetH hdsSrc;
VRTDatasetH hdsOv;
VRTSourcedRasterBandH hbandOv;
double gtOv[6] = {0.};
int dimOv[2] = {0};
int j = 0;
int factor;
const char *ovtable = NULL;
VRTDatasetH hdsDst;
VRTSourcedRasterBandH hbandDst;
int tile_size[2] = {0};
int _tile_size[2] = {0};
int ntiles[2] = {1, 1};
int xtile = 0;
int ytile = 0;
double gt[6] = {0.};
rt_raster rast = NULL;
char *hex;
uint32_t hexlen = 0;
hdsSrc = GDALOpenShared(config->rt_file[idx], GA_ReadOnly);
if (hdsSrc == NULL) {
rterror(_("build_overview: Could not open raster: %s"), config->rt_file[idx]);
return 0;
}
/* working copy of geotransform matrix */
memcpy(gtOv, info->gt, sizeof(double) * 6);
if (ovx >= config->overview_count) {
rterror(_("build_overview: Invalid overview index: %d"), ovx);
return 0;
}
factor = config->overview[ovx];
ovtable = (const char *) config->overview_table[ovx];
/* factor must be within valid range */
if (factor < MINOVFACTOR || factor > MAXOVFACTOR) {
rterror(_("build_overview: Overview factor %d is not between %d and %d"), factor, MINOVFACTOR, MAXOVFACTOR);
return 0;
}
dimOv[0] = (int) (info->dim[0] + (factor / 2)) / factor;
dimOv[1] = (int) (info->dim[1] + (factor / 2)) / factor;
/* create VRT dataset */
hdsOv = VRTCreate(dimOv[0], dimOv[1]);
/*
GDALSetDescription(hdsOv, "/tmp/ov.vrt");
*/
GDALSetProjection(hdsOv, info->srs);
/* adjust scale */
gtOv[1] *= factor;
gtOv[5] *= factor;
GDALSetGeoTransform(hdsOv, gtOv);
/* add bands as simple sources */
for (j = 0; j < info->nband_count; j++) {
GDALAddBand(hdsOv, info->gdalbandtype[j], NULL);
hbandOv = (VRTSourcedRasterBandH) GDALGetRasterBand(hdsOv, j + 1);
if (info->hasnodata[j])
GDALSetRasterNoDataValue(hbandOv, info->nodataval[j]);
VRTAddSimpleSource(
hbandOv, GDALGetRasterBand(hdsSrc, info->nband[j]),
0, 0,
info->dim[0], info->dim[1],
0, 0,
dimOv[0], dimOv[1],
"near", VRT_NODATA_UNSET
);
}
/* make sure VRT reflects all changes */
VRTFlushCache(hdsOv);
/* decide on tile size */
if (!config->tile_size[0])
tile_size[0] = dimOv[0];
else
tile_size[0] = config->tile_size[0];
if (!config->tile_size[1])
tile_size[1] = dimOv[1];
else
tile_size[1] = config->tile_size[1];
/* number of tiles */
if (
tile_size[0] != dimOv[0] &&
tile_size[1] != dimOv[1]
) {
ntiles[0] = (dimOv[0] + tile_size[0] - 1) / tile_size[0];
ntiles[1] = (dimOv[1] + tile_size[1] - 1) / tile_size[1];
}
/* working copy of geotransform matrix */
memcpy(gt, gtOv, sizeof(double) * 6);
/* tile overview */
/* each tile is a VRT with constraints set for just the data required for the tile */
for (ytile = 0; ytile < ntiles[1]; ytile++) {
/* edge y tile */
if (!config->pad_tile && ntiles[1] > 1 && (ytile + 1) == ntiles[1])
_tile_size[1] = dimOv[1] - (ytile * tile_size[1]);
else
_tile_size[1] = tile_size[1];
for (xtile = 0; xtile < ntiles[0]; xtile++) {
/*
char fn[100];
sprintf(fn, "/tmp/ovtile%d.vrt", (ytile * ntiles[0]) + xtile);
*/
/* edge x tile */
if (!config->pad_tile && ntiles[0] > 1 && (xtile + 1) == ntiles[0])
_tile_size[0] = dimOv[0] - (xtile * tile_size[0]);
else
_tile_size[0] = tile_size[0];
/* compute tile's upper-left corner */
GDALApplyGeoTransform(
gtOv,
xtile * tile_size[0], ytile * tile_size[1],
&(gt[0]), &(gt[3])
);
/* create VRT dataset */
hdsDst = VRTCreate(_tile_size[0], _tile_size[1]);
/*
GDALSetDescription(hdsDst, fn);
*/
GDALSetProjection(hdsDst, info->srs);
GDALSetGeoTransform(hdsDst, gt);
/* add bands as simple sources */
for (j = 0; j < info->nband_count; j++) {
GDALAddBand(hdsDst, info->gdalbandtype[j], NULL);
hbandDst = (VRTSourcedRasterBandH) GDALGetRasterBand(hdsDst, j + 1);
if (info->hasnodata[j])
GDALSetRasterNoDataValue(hbandDst, info->nodataval[j]);
VRTAddSimpleSource(
hbandDst, GDALGetRasterBand(hdsOv, j + 1),
xtile * tile_size[0], ytile * tile_size[1],
_tile_size[0], _tile_size[1],
0, 0,
_tile_size[0], _tile_size[1],
"near", VRT_NODATA_UNSET
);
}
/* make sure VRT reflects all changes */
VRTFlushCache(hdsDst);
/* convert VRT dataset to rt_raster */
rast = rt_raster_from_gdal_dataset(hdsDst);
if (rast == NULL) {
rterror(_("build_overview: Could not convert VRT dataset to PostGIS raster"));
GDALClose(hdsDst);
return 0;
}
/* set srid if provided */
rt_raster_set_srid(rast, info->srid);
/* convert rt_raster to hexwkb */
hex = rt_raster_to_hexwkb(rast, FALSE, &hexlen);
raster_destroy(rast);
if (hex == NULL) {
rterror(_("build_overview: Could not convert PostGIS raster to hex WKB"));
GDALClose(hdsDst);
return 0;
}
/* add hexwkb to tileset */
append_stringbuffer(tileset, hex);
GDALClose(hdsDst);
/* flush if tileset gets too big */
if (tileset->length > 10) {
if (!insert_records(
config->schema, ovtable, config->raster_column,
(config->file_column ? config->rt_filename[idx] : NULL), config->file_column_name,
config->copy_statements, config->out_srid,
tileset, buffer
)) {
rterror(_("build_overview: Could not convert raster tiles into INSERT or COPY statements"));
GDALClose(hdsSrc);
return 0;
}
rtdealloc_stringbuffer(tileset, 0);
}
}
}
GDALClose(hdsOv);
GDALClose(hdsSrc);
return 1;
}
static int
convert_raster(int idx, RTLOADERCFG *config, RASTERINFO *info, STRINGBUFFER *tileset, STRINGBUFFER *buffer) {
GDALDatasetH hdsSrc;
GDALRasterBandH hbandSrc;
int nband = 0;
int i = 0;
int ntiles[2] = {1, 1};
int _tile_size[2] = {0, 0};
int xtile = 0;
int ytile = 0;
double gt[6] = {0.};
const char* pszProjectionRef = NULL;
int tilesize = 0;
rt_raster rast = NULL;
int numbands = 0;
rt_band band = NULL;
char *hex;
uint32_t hexlen = 0;
info->srid = config->srid;
hdsSrc = GDALOpenShared(config->rt_file[idx], GA_ReadOnly);
if (hdsSrc == NULL) {
rterror(_("convert_raster: Could not open raster: %s"), config->rt_file[idx]);
return 0;
}
nband = GDALGetRasterCount(hdsSrc);
if (!nband) {
rterror(_("convert_raster: No bands found in raster: %s"), config->rt_file[idx]);
GDALClose(hdsSrc);
return 0;
}
/* check that bands specified are available */
for (i = 0; i < config->nband_count; i++) {
if (config->nband[i] > nband) {
rterror(_("convert_raster: Band %d not found in raster: %s"), config->nband[i], config->rt_file[idx]);
GDALClose(hdsSrc);
return 0;
}
}
/* record srs */
pszProjectionRef = GDALGetProjectionRef(hdsSrc);
if (pszProjectionRef != NULL && pszProjectionRef[0] != '\0') {
info->srs = rtalloc(sizeof(char) * (strlen(pszProjectionRef) + 1));
if (info->srs == NULL) {
rterror(_("convert_raster: Could not allocate memory for storing SRS"));
GDALClose(hdsSrc);
return 0;
}
strcpy(info->srs, pszProjectionRef);
if (info->srid == SRID_UNKNOWN) {
OGRSpatialReferenceH hSRS = OSRNewSpatialReference(NULL);
if (OSRSetFromUserInput(hSRS, pszProjectionRef) == OGRERR_NONE) {
const char* pszAuthorityName = OSRGetAuthorityName(hSRS, NULL);
const char* pszAuthorityCode = OSRGetAuthorityCode(hSRS, NULL);
if (
pszAuthorityName != NULL &&
strcmp(pszAuthorityName, "EPSG") == 0 &&
pszAuthorityCode != NULL
) {
info->srid = atoi(pszAuthorityCode);
}
}
OSRDestroySpatialReference(hSRS);
}
}
if ( info->srid == SRID_UNKNOWN && config->out_srid != SRID_UNKNOWN ) {
rterror(_("convert_raster: could not determine source srid, cannot transform to target srid %d"), config->out_srid);
GDALClose(hdsSrc);
return 0;
}
/* record geotransform matrix */
if (GDALGetGeoTransform(hdsSrc, info->gt) != CE_None) {
rtinfo(_("Using default geotransform matrix (0, 1, 0, 0, 0, -1) for raster: %s"), config->rt_file[idx]);
info->gt[0] = 0;
info->gt[1] = 1;
info->gt[2] = 0;
info->gt[3] = 0;
info->gt[4] = 0;
info->gt[5] = -1;
}
memcpy(gt, info->gt, sizeof(double) * 6);
/* record # of bands */
/* user-specified bands */
if (config->nband_count > 0) {
info->nband_count = config->nband_count;
info->nband = rtalloc(sizeof(int) * info->nband_count);
if (info->nband == NULL) {
rterror(_("convert_raster: Could not allocate memory for storing band indices"));
GDALClose(hdsSrc);
return 0;
}
memcpy(info->nband, config->nband, sizeof(int) * info->nband_count);
}
/* all bands */
else {
info->nband_count = nband;
info->nband = rtalloc(sizeof(int) * info->nband_count);
if (info->nband == NULL) {
rterror(_("convert_raster: Could not allocate memory for storing band indices"));
GDALClose(hdsSrc);
return 0;
}
for (i = 0; i < info->nband_count; i++)
info->nband[i] = i + 1;
}
/* initialize parameters dependent on nband */
info->gdalbandtype = rtalloc(sizeof(GDALDataType) * info->nband_count);
if (info->gdalbandtype == NULL) {
rterror(_("convert_raster: Could not allocate memory for storing GDAL data type"));
GDALClose(hdsSrc);
return 0;
}
info->bandtype = rtalloc(sizeof(rt_pixtype) * info->nband_count);
if (info->bandtype == NULL) {
rterror(_("convert_raster: Could not allocate memory for storing pixel type"));
GDALClose(hdsSrc);
return 0;
}
info->hasnodata = rtalloc(sizeof(int) * info->nband_count);
if (info->hasnodata == NULL) {
rterror(_("convert_raster: Could not allocate memory for storing hasnodata flag"));
GDALClose(hdsSrc);
return 0;
}
info->nodataval = rtalloc(sizeof(double) * info->nband_count);
if (info->nodataval == NULL) {
rterror(_("convert_raster: Could not allocate memory for storing nodata value"));
GDALClose(hdsSrc);
return 0;
}
memset(info->gdalbandtype, GDT_Unknown, sizeof(GDALDataType) * info->nband_count);
memset(info->bandtype, PT_END, sizeof(rt_pixtype) * info->nband_count);
memset(info->hasnodata, 0, sizeof(int) * info->nband_count);
memset(info->nodataval, 0, sizeof(double) * info->nband_count);
/* dimensions of raster */
info->dim[0] = GDALGetRasterXSize(hdsSrc);
info->dim[1] = GDALGetRasterYSize(hdsSrc);
/* tile size is "auto" */
if (
config->tile_size[0] == -1 &&
config->tile_size[1] == -1
) {
calc_tile_size(
info->dim[0], info->dim[1],
&(config->tile_size[0]), &(config->tile_size[1])
);
rtinfo(_("Using computed tile size: %dx%d"), config->tile_size[0], config->tile_size[1]);
}
/* decide on tile size */
if (!config->tile_size[0])
info->tile_size[0] = info->dim[0];
else
info->tile_size[0] = config->tile_size[0];
if (!config->tile_size[1])
info->tile_size[1] = info->dim[1];
else
info->tile_size[1] = config->tile_size[1];
/* number of tiles */
if (info->tile_size[0] != info->dim[0])
ntiles[0] = (info->dim[0] + info->tile_size[0] - 1) / info->tile_size[0];
if (info->tile_size[1] != info->dim[1])
ntiles[1] = (info->dim[1] + info->tile_size[1] - 1) / info->tile_size[1];
/* estimate size of 1 tile */
tilesize = info->tile_size[0] * info->tile_size[1];
/* go through bands for attributes */
for (i = 0; i < info->nband_count; i++) {
hbandSrc = GDALGetRasterBand(hdsSrc, info->nband[i]);
/* datatype */
info->gdalbandtype[i] = GDALGetRasterDataType(hbandSrc);
/* complex data type? */
if (GDALDataTypeIsComplex(info->gdalbandtype[i])) {
rterror(_("convert_raster: The pixel type of band %d is a complex data type. PostGIS raster does not support complex data types"), i + 1);
GDALClose(hdsSrc);
return 0;
}
/* convert data type to that of postgis raster */
info->bandtype[i] = rt_util_gdal_datatype_to_pixtype(info->gdalbandtype[i]);
/* hasnodata and nodataval */
info->nodataval[i] = GDALGetRasterNoDataValue(hbandSrc, &(info->hasnodata[i]));
if (!info->hasnodata[i]) {
/* does NOT have nodata value, but user-specified */
if (config->hasnodata) {
info->hasnodata[i] = 1;
info->nodataval[i] = config->nodataval;
}
else
info->nodataval[i] = 0;
}
/* update estimated size of 1 tile */
tilesize *= rt_pixtype_size(info->bandtype[i]);
}
/* roughly estimate size of one tile and all bands */
tilesize *= 1.1;
if (tilesize > MAXTILESIZE)
rtwarn(_("The size of each output tile may exceed 1 GB. Use -t to specify a reasonable tile size"));
/* out-db raster */
if (config->outdb) {
GDALClose(hdsSrc);
/* each tile is a raster */
for (ytile = 0; ytile < ntiles[1]; ytile++) {
/* edge y tile */
if (!config->pad_tile && ntiles[1] > 1 && (ytile + 1) == ntiles[1])
_tile_size[1] = info->dim[1] - (ytile * info->tile_size[1]);
else
_tile_size[1] = info->tile_size[1];
for (xtile = 0; xtile < ntiles[0]; xtile++) {
/* edge x tile */
if (!config->pad_tile && ntiles[0] > 1 && (xtile + 1) == ntiles[0])
_tile_size[0] = info->dim[0] - (xtile * info->tile_size[0]);
else
_tile_size[0] = info->tile_size[0];
/* compute tile's upper-left corner */
GDALApplyGeoTransform(
info->gt,
xtile * info->tile_size[0], ytile * info->tile_size[1],
&(gt[0]), &(gt[3])
);
/* create raster object */
rast = rt_raster_new(_tile_size[0], _tile_size[1]);
if (rast == NULL) {
rterror(_("convert_raster: Could not create raster"));
return 0;
}
/* set raster attributes */
rt_raster_set_srid(rast, info->srid);
rt_raster_set_geotransform_matrix(rast, gt);
/* add bands */
for (i = 0; i < info->nband_count; i++) {
band = rt_band_new_offline(
_tile_size[0], _tile_size[1],
info->bandtype[i],
info->hasnodata[i], info->nodataval[i],
info->nband[i] - 1,
config->rt_file[idx]
);
if (band == NULL) {
rterror(_("convert_raster: Could not create offline band"));
raster_destroy(rast);
return 0;
}
/* add band to raster */
if (rt_raster_add_band(rast, band, rt_raster_get_num_bands(rast)) == -1) {
rterror(_("convert_raster: Could not add offlineband to raster"));
rt_band_destroy(band);
raster_destroy(rast);
return 0;
}
/* inspect each band of raster where band is NODATA */
if (!config->skip_nodataval_check)
rt_band_check_is_nodata(band);
}
/* convert rt_raster to hexwkb */
hex = rt_raster_to_hexwkb(rast, FALSE, &hexlen);
raster_destroy(rast);
if (hex == NULL) {
rterror(_("convert_raster: Could not convert PostGIS raster to hex WKB"));
return 0;
}
/* add hexwkb to tileset */
append_stringbuffer(tileset, hex);
/* flush if tileset gets too big */
if (tileset->length > 10) {
if (!insert_records(
config->schema, config->table, config->raster_column,
(config->file_column ? config->rt_filename[idx] : NULL), config->file_column_name,
config->copy_statements, config->out_srid,
tileset, buffer
)) {
rterror(_("convert_raster: Could not convert raster tiles into INSERT or COPY statements"));
return 0;
}
rtdealloc_stringbuffer(tileset, 0);
}
}
}
}
/* in-db raster */
else {
VRTDatasetH hdsDst;
VRTSourcedRasterBandH hbandDst;
/* each tile is a VRT with constraints set for just the data required for the tile */
for (ytile = 0; ytile < ntiles[1]; ytile++) {
/* edge y tile */
if (!config->pad_tile && ntiles[1] > 1 && (ytile + 1) == ntiles[1])
_tile_size[1] = info->dim[1] - (ytile * info->tile_size[1]);
else
_tile_size[1] = info->tile_size[1];
for (xtile = 0; xtile < ntiles[0]; xtile++) {
/*
char fn[100];
sprintf(fn, "/tmp/tile%d.vrt", (ytile * ntiles[0]) + xtile);
*/
/* edge x tile */
if (!config->pad_tile && ntiles[0] > 1 && (xtile + 1) == ntiles[0])
_tile_size[0] = info->dim[0] - (xtile * info->tile_size[0]);
else
_tile_size[0] = info->tile_size[0];
/* compute tile's upper-left corner */
GDALApplyGeoTransform(
info->gt,
xtile * info->tile_size[0], ytile * info->tile_size[1],
&(gt[0]), &(gt[3])
);
/*
rtinfo(_("tile (%d, %d) gt = (%f, %f, %f, %f, %f, %f)"),
xtile, ytile,
gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]
);
*/
/* create VRT dataset */
hdsDst = VRTCreate(_tile_size[0], _tile_size[1]);
/*
GDALSetDescription(hdsDst, fn);
*/
GDALSetProjection(hdsDst, info->srs);
GDALSetGeoTransform(hdsDst, gt);
/* add bands as simple sources */
for (i = 0; i < info->nband_count; i++) {
GDALAddBand(hdsDst, info->gdalbandtype[i], NULL);
hbandDst = (VRTSourcedRasterBandH) GDALGetRasterBand(hdsDst, i + 1);
if (info->hasnodata[i])
GDALSetRasterNoDataValue(hbandDst, info->nodataval[i]);
VRTAddSimpleSource(
hbandDst, GDALGetRasterBand(hdsSrc, info->nband[i]),
xtile * info->tile_size[0], ytile * info->tile_size[1],
_tile_size[0], _tile_size[1],
0, 0,
_tile_size[0], _tile_size[1],
"near", VRT_NODATA_UNSET
);
}
/* make sure VRT reflects all changes */
VRTFlushCache(hdsDst);
/* convert VRT dataset to rt_raster */
rast = rt_raster_from_gdal_dataset(hdsDst);
if (rast == NULL) {
rterror(_("convert_raster: Could not convert VRT dataset to PostGIS raster"));
GDALClose(hdsDst);
return 0;
}
/* set srid if provided */
rt_raster_set_srid(rast, info->srid);
/* inspect each band of raster where band is NODATA */
numbands = rt_raster_get_num_bands(rast);
for (i = 0; i < numbands; i++) {
band = rt_raster_get_band(rast, i);
if (band != NULL && !config->skip_nodataval_check)
rt_band_check_is_nodata(band);
}
/* convert rt_raster to hexwkb */
hex = rt_raster_to_hexwkb(rast, FALSE, &hexlen);
raster_destroy(rast);
if (hex == NULL) {
rterror(_("convert_raster: Could not convert PostGIS raster to hex WKB"));
GDALClose(hdsDst);
return 0;
}
/* add hexwkb to tileset */
append_stringbuffer(tileset, hex);
GDALClose(hdsDst);
/* flush if tileset gets too big */
if (tileset->length > 10) {
if (!insert_records(
config->schema, config->table, config->raster_column,
(config->file_column ? config->rt_filename[idx] : NULL), config->file_column_name,
config->copy_statements, config->out_srid,
tileset, buffer
)) {
rterror(_("convert_raster: Could not convert raster tiles into INSERT or COPY statements"));
GDALClose(hdsSrc);
return 0;
}
rtdealloc_stringbuffer(tileset, 0);
}
}
}
GDALClose(hdsSrc);
}
return 1;
}
static int
process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) {
int i = 0;
assert(config != NULL);
assert(config->table != NULL);
assert(config->raster_column != NULL);
if (config->transaction) {
if (!append_sql_to_buffer(buffer, strdup("BEGIN;"))) {
rterror(_("process_rasters: Could not add BEGIN statement to string buffer"));
return 0;
}
}
/* drop table */
if (config->opt == 'd') {
if (!drop_table(config->schema, config->table, buffer)) {
rterror(_("process_rasters: Could not add DROP TABLE statement to string buffer"));
return 0;
}
if (config->overview_count) {
for (i = 0; i < config->overview_count; i++) {
if (!drop_table(config->schema, config->overview_table[i], buffer)) {
rterror(_("process_rasters: Could not add an overview's DROP TABLE statement to string buffer"));
return 0;
}
}
}
}
/* create table */
if (config->opt != 'a') {
if (!create_table(
config->schema, config->table, config->raster_column,
config->file_column, config->file_column_name,
config->tablespace, config->idx_tablespace,
buffer
)) {
rterror(_("process_rasters: Could not add CREATE TABLE statement to string buffer"));
return 0;
}
if (config->overview_count) {
for (i = 0; i < config->overview_count; i++) {
if (!create_table(
config->schema, config->overview_table[i], config->raster_column,
config->file_column, config->file_column_name,
config->tablespace, config->idx_tablespace,
buffer
)) {
rterror(_("process_rasters: Could not add an overview's CREATE TABLE statement to string buffer"));
return 0;
}
}
}
}
/* no need to run if opt is 'p' */
if (config->opt != 'p') {
RASTERINFO refinfo;
init_rastinfo(&refinfo);
/* process each raster */
for (i = 0; i < config->rt_file_count; i++) {
RASTERINFO rastinfo;
STRINGBUFFER tileset;
fprintf(stderr, _("Processing %d/%d: %s\n"), i + 1, config->rt_file_count, config->rt_file[i]);
init_rastinfo(&rastinfo);
init_stringbuffer(&tileset);
/* convert raster */
if (!convert_raster(i, config, &rastinfo, &tileset, buffer)) {
rterror(_("process_rasters: Could not process raster: %s"), config->rt_file[i]);
rtdealloc_rastinfo(&rastinfo);
rtdealloc_stringbuffer(&tileset, 0);
return 0;
}
/* process raster tiles into COPY or INSERT statements */
if (tileset.length && !insert_records(
config->schema, config->table, config->raster_column,
(config->file_column ? config->rt_filename[i] : NULL),
config->file_column_name,
config->copy_statements, config->out_srid,
&tileset, buffer
)) {
rterror(_("process_rasters: Could not convert raster tiles into INSERT or COPY statements"));
rtdealloc_rastinfo(&rastinfo);
rtdealloc_stringbuffer(&tileset, 0);
return 0;
}
rtdealloc_stringbuffer(&tileset, 0);
/* flush buffer after every raster */
flush_stringbuffer(buffer);
/* overviews */
if (config->overview_count) {
int j = 0;
for (j = 0; j < config->overview_count; j++) {
if (!build_overview(i, config, &rastinfo, j, &tileset, buffer)) {
rterror(_("process_rasters: Could not create overview of factor %d for raster %s"), config->overview[j], config->rt_file[i]);
rtdealloc_rastinfo(&rastinfo);
rtdealloc_stringbuffer(&tileset, 0);
return 0;
}
if (tileset.length && !insert_records(
config->schema, config->overview_table[j], config->raster_column,
(config->file_column ? config->rt_filename[i] : NULL), config->file_column_name,
config->copy_statements, config->out_srid,
&tileset, buffer
)) {
rterror(_("process_rasters: Could not convert overview tiles into INSERT or COPY statements"));
rtdealloc_rastinfo(&rastinfo);
rtdealloc_stringbuffer(&tileset, 0);
return 0;
}
rtdealloc_stringbuffer(&tileset, 0);
/* flush buffer after every raster */
flush_stringbuffer(buffer);
}
}
if (config->rt_file_count > 1) {
if (i < 1)
copy_rastinfo(&refinfo, &rastinfo);
else {
diff_rastinfo(&rastinfo, &refinfo);
}
}
rtdealloc_rastinfo(&rastinfo);
}
rtdealloc_rastinfo(&refinfo);
}
/* index */
if (config->idx) {
/* create index */
if (!create_index(
config->schema, config->table, config->raster_column,
config->idx_tablespace,
buffer
)) {
rterror(_("process_rasters: Could not add CREATE INDEX statement to string buffer"));
return 0;
}
/* analyze */
if (config->opt != 'p') {
if (!analyze_table(
config->schema, config->table,
buffer
)) {
rterror(_("process_rasters: Could not add ANALYZE statement to string buffer"));
return 0;
}
}
if (config->overview_count) {
for (i = 0; i < config->overview_count; i++) {
/* create index */
if (!create_index(
config->schema, config->overview_table[i], config->raster_column,
config->idx_tablespace,
buffer
)) {
rterror(_("process_rasters: Could not add an overview's CREATE INDEX statement to string buffer"));
return 0;
}
/* analyze */
if (config->opt != 'p') {
if (!analyze_table(
config->schema, config->overview_table[i],
buffer
)) {
rterror(_("process_rasters: Could not add an overview's ANALYZE statement to string buffer"));
return 0;
}
}
}
}
}
/* add constraints */
if (config->constraints) {
if (!add_raster_constraints(
config->schema, config->table, config->raster_column,
config->regular_blocking, config->max_extent,
buffer
)) {
rterror(_("process:rasters: Could not add AddRasterConstraints statement to string buffer"));
return 0;
}
if (config->overview_count) {
for (i = 0; i < config->overview_count; i++) {
if (!add_raster_constraints(
config->schema, config->overview_table[i], config->raster_column,
config->regular_blocking, config->max_extent,
buffer
)) {
rterror(_("process_rasters: Could not add an overview's AddRasterConstraints statement to string buffer"));
return 0;
}
}
}
}
/* overview constraint is automatically added */
if (config->overview_count) {
for (i = 0; i < config->overview_count; i++) {
if (!add_overview_constraints(
config->schema, config->overview_table[i], config->raster_column,
config->schema, config->table, config->raster_column,
config->overview[i],
buffer
)) {
rterror(_("process_rasters: Could not add an overview's AddOverviewConstraints statement to string buffer"));
return 0;
}
}
}
if (config->transaction) {
if (!append_sql_to_buffer(buffer, strdup("END;"))) {
rterror(_("process_rasters: Could not add END statement to string buffer"));
return 0;
}
}
/* maintenance */
if (config->opt != 'p' && config->maintenance) {
if (!vacuum_table(
config->schema, config->table,
buffer
)) {
rterror(_("process_rasters: Could not add VACUUM statement to string buffer"));
return 0;
}
if (config->overview_count) {
for (i = 0; i < config->overview_count; i++) {
if (!vacuum_table(
config->schema, config->overview_table[i],
buffer
)) {
rterror(_("process_rasters: Could not add an overview's VACUUM statement to string buffer"));
return 0;
}
}
}
}
return 1;
}
int
main(int argc, char **argv) {
RTLOADERCFG *config = NULL;
STRINGBUFFER *buffer = NULL;
int i = 0;
int j = 0;
char **elements = NULL;
int n = 0;
GDALDriverH drv = NULL;
char *tmp = NULL;
#ifdef USE_NLS
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
#endif
/* no args, show usage */
if (argc == 1) {
usage();
exit(0);
}
/* initialize config */
config = rtalloc(sizeof(RTLOADERCFG));
if (config == NULL) {
rterror(_("Could not allocate memory for loader configuration"));
exit(1);
}
init_config(config);
/****************************************************************************
* parse arguments
****************************************************************************/
for (i = 1; i < argc; i++) {
char *optarg, *ptr;
/* srid */
if (CSEQUAL(argv[i], "-s") && i < argc - 1) {
optarg = argv[++i];
ptr = strchr(optarg, ':');
if (ptr) {
*ptr++ = '\0';
sscanf(optarg, "%d", &config->srid);
sscanf(ptr, "%d", &config->out_srid);
} else {
config->srid = config->out_srid = atoi(optarg);
}
}
/* band index */
else if (CSEQUAL(argv[i], "-b") && i < argc - 1) {
elements = strsplit(argv[++i], ",", &n);
if (n < 1) {
rterror(_("Could not process -b"));
rtdealloc_config(config);
exit(1);
}
config->nband_count = 0;
for (j = 0; j < n; j++) {
char *t = trim(elements[j]);
char **minmax = NULL;
int *range = NULL;
int p = 0;
int l = 0;
int m = 0;
int o = 0;
/* is t a range? */
minmax = strsplit(t, "-", &o);
if (o == 2) {
if (!array_range(atoi(minmax[0]), atoi(minmax[1]), 1, &range, &p)) {
rterror(_("Could not allocate memory for storing band indices"));
for (l = 0; l < o; l++)
rtdealloc(minmax[l]);
rtdealloc(minmax);
for (j = 0; j < n; j++)
rtdealloc(elements[j]);
rtdealloc(elements);
rtdealloc(t);
rtdealloc_config(config);
exit(1);
}
}
else {
p = 1;
range = rtalloc(sizeof(int));
if (range == NULL) {
rterror(_("Could not allocate memory for storing band indices"));
for (l = 0; l < o; l++)
rtdealloc(minmax[l]);
rtdealloc(minmax);
for (j = 0; j < n; j++)
rtdealloc(elements[j]);
rtdealloc(elements);
rtdealloc(t);
rtdealloc_config(config);
exit(1);
}
*range = atoi(t);
}
m = config->nband_count;
config->nband_count += p;
config->nband = rtrealloc(config->nband, sizeof(int) * config->nband_count);
if (config->nband == NULL) {
rterror(_("Could not allocate memory for storing band indices"));
rtdealloc(range);
for (l = 0; l < o; l++)
rtdealloc(minmax[l]);
rtdealloc(minmax);
for (j = 0; j < n; j++)
rtdealloc(elements[j]);
rtdealloc(elements);
rtdealloc(t);
rtdealloc_config(config);
exit(1);
}
for (l = 0; l < p; l++, m++)
config->nband[m] = range[l];
rtdealloc(range);
for (l = 0; l < o; l++)
rtdealloc(minmax[l]);
rtdealloc(minmax);
rtdealloc(t);
rtdealloc(elements[j]);
}
rtdealloc(elements);
elements = NULL;
n = 0;
for (j = 0; j < config->nband_count; j++) {
if (config->nband[j] < 1) {
rterror(_("Band index %d must be greater than 0"), config->nband[j]);
rtdealloc_config(config);
exit(1);
}
}
}
/* tile size */
else if (CSEQUAL(argv[i], "-t") && i < argc - 1) {
if (CSEQUAL(argv[++i], "auto")) {
config->tile_size[0] = -1;
config->tile_size[1] = -1;
}
else {
elements = strsplit(argv[i], "x", &n);
if (n != 2) {
rterror(_("Could not process -t"));
rtdealloc_config(config);
exit(1);
}
for (j = 0; j < n; j++) {
char *t = trim(elements[j]);
config->tile_size[j] = atoi(t);
rtdealloc(t);
rtdealloc(elements[j]);
}
rtdealloc(elements);
elements = NULL;
n = 0;
for (j = 0; j < 2; j++) {
if (config->tile_size[j] < 1) {
rterror(_("Tile size must be greater than 0x0"));
rtdealloc_config(config);
exit(1);
}
}
}
}
/* pad tiles */
else if (CSEQUAL(argv[i], "-P")) {
config->pad_tile = 1;
}
/* out-of-db raster */
else if (CSEQUAL(argv[i], "-R")) {
config->outdb = 1;
}
/* drop table and recreate */
else if (CSEQUAL(argv[i], "-d")) {
config->opt = 'd';
}
/* append to table */
else if (CSEQUAL(argv[i], "-a")) {
config->opt = 'a';
}
/* create new table */
else if (CSEQUAL(argv[i], "-c")) {
config->opt = 'c';
}
/* prepare only */
else if (CSEQUAL(argv[i], "-p")) {
config->opt = 'p';
}
/* raster column name */
else if (CSEQUAL(argv[i], "-f") && i < argc - 1) {
config->raster_column = rtalloc(sizeof(char) * (strlen(argv[++i]) + 1));
if (config->raster_column == NULL) {
rterror(_("Could not allocate memory for storing raster column name"));
rtdealloc_config(config);
exit(1);
}
strncpy(config->raster_column, argv[i], strlen(argv[i]) + 1);
}
/* filename column */
else if (CSEQUAL(argv[i], "-F")) {
config->file_column = 1;
}
/* filename column name */
else if (CSEQUAL(argv[i], "-n") && i < argc - 1) {
config->file_column_name = rtalloc(sizeof(char) * (strlen(argv[++i]) + 1));
if (config->file_column_name == NULL) {
rterror(_("Could not allocate memory for storing filename column name"));
rtdealloc_config(config);
exit(1);
}
strncpy(config->file_column_name, argv[i], strlen(argv[i]) + 1);
config->file_column = 1;
}
/* overview factors */
else if (CSEQUAL(argv[i], "-l") && i < argc - 1) {
elements = strsplit(argv[++i], ",", &n);
if (n < 1) {
rterror(_("Could not process -l"));
rtdealloc_config(config);
exit(1);
}
config->overview_count = n;
config->overview = rtalloc(sizeof(int) * n);
if (config->overview == NULL) {
rterror(_("Could not allocate memory for storing overview factors"));
rtdealloc_config(config);
exit(1);
}
for (j = 0; j < n; j++) {
char *t = trim(elements[j]);
config->overview[j] = atoi(t);
rtdealloc(t);
rtdealloc(elements[j]);
}
rtdealloc(elements);
elements = NULL;
n = 0;
for (j = 0; j < config->overview_count; j++) {
if (config->overview[j] < MINOVFACTOR || config->overview[j] > MAXOVFACTOR) {
rterror(_("Overview factor %d is not between %d and %d"), config->overview[j], MINOVFACTOR, MAXOVFACTOR);
rtdealloc_config(config);
exit(1);
}
}
}
/* quote identifiers */
else if (CSEQUAL(argv[i], "-q")) {
config->quoteident = 1;
}
/* create index */
else if (CSEQUAL(argv[i], "-I")) {
config->idx = 1;
}
/* maintenance */
else if (CSEQUAL(argv[i], "-M")) {
config->maintenance = 1;
}
/* set constraints */
else if (CSEQUAL(argv[i], "-C")) {
config->constraints = 1;
}
/* disable extent constraint */
else if (CSEQUAL(argv[i], "-x")) {
config->max_extent = 0;
}
/* enable regular_blocking */
else if (CSEQUAL(argv[i], "-r")) {
config->regular_blocking = 1;
}
/* tablespace of new table */
else if (CSEQUAL(argv[i], "-T") && i < argc - 1) {
config->tablespace = rtalloc(sizeof(char) * (strlen(argv[++i]) + 1));
if (config->tablespace == NULL) {
rterror(_("Could not allocate memory for storing tablespace of new table"));
rtdealloc_config(config);
exit(1);
}
strncpy(config->tablespace, argv[i], strlen(argv[i]) + 1);
}
/* tablespace of new index */
else if (CSEQUAL(argv[i], "-X") && i < argc - 1) {
config->idx_tablespace = rtalloc(sizeof(char) * (strlen(argv[++i]) + 1));
if (config->idx_tablespace == NULL) {
rterror(_("Could not allocate memory for storing tablespace of new indices"));
rtdealloc_config(config);
exit(1);
}
strncpy(config->idx_tablespace, argv[i], strlen(argv[i]) + 1);
}
/* nodata value */
else if (CSEQUAL(argv[i], "-N") && i < argc - 1) {
config->hasnodata = 1;
config->nodataval = atof(argv[++i]);
}
/* skip NODATA value check for bands */
else if (CSEQUAL(argv[i], "-k")) {
config->skip_nodataval_check = 1;
}
/* endianness */
else if (CSEQUAL(argv[i], "-E") && i < argc - 1) {
config->endian = atoi(argv[++i]);
config->endian = 1;
}
/* version */
else if (CSEQUAL(argv[i], "-V") && i < argc - 1) {
config->version = atoi(argv[++i]);
config->version = 0;
}
/* transaction */
else if (CSEQUAL(argv[i], "-e")) {
config->transaction = 0;
}
/* COPY statements */
else if (CSEQUAL(argv[i], "-Y")) {
config->copy_statements = 1;
}
/* GDAL formats */
else if (CSEQUAL(argv[i], "-G")) {
uint32_t drv_count = 0;
rt_gdaldriver drv_set = rt_raster_gdal_drivers(&drv_count, 0);
if (drv_set == NULL || !drv_count) {
rterror(_("Could not get list of available GDAL raster formats"));
}
else {
printf(_("Supported GDAL raster formats:\n"));
for (j = 0; j < drv_count; j++) {
printf(_(" %s\n"), drv_set[j].long_name);
rtdealloc(drv_set[j].short_name);
rtdealloc(drv_set[j].long_name);
rtdealloc(drv_set[j].create_options);
}
rtdealloc(drv_set);
}
rtdealloc_config(config);
exit(0);
}
/* help */
else if (CSEQUAL(argv[i], "-?")) {
usage();
rtdealloc_config(config);
exit(0);
}
else {
config->rt_file_count++;
config->rt_file = (char **) rtrealloc(config->rt_file, sizeof(char *) * config->rt_file_count);
if (config->rt_file == NULL) {
rterror(_("Could not allocate memory for storing raster files"));
rtdealloc_config(config);
exit(1);
}
config->rt_file[config->rt_file_count - 1] = rtalloc(sizeof(char) * (strlen(argv[i]) + 1));
if (config->rt_file[config->rt_file_count - 1] == NULL) {
rterror(_("Could not allocate memory for storing raster filename"));
rtdealloc_config(config);
exit(1);
}
strncpy(config->rt_file[config->rt_file_count - 1], argv[i], strlen(argv[i]) + 1);
}
}
if (config->srid != config->out_srid) {
if (config->copy_statements) {
rterror(_("Invalid argument combination - cannot use -Y with -s FROM_SRID:TO_SRID"));
exit(1);
}
if (config->out_srid == SRID_UNKNOWN) {
rterror(_("Unknown target SRID is invalid when source SRID is given"));
exit(1);
}
}
/* register GDAL drivers */
GDALAllRegister();
/* no files provided */
if (!config->rt_file_count) {
rterror(_("No raster provided"));
rtdealloc_config(config);
exit(1);
}
/*
at least two files, see if last is table
last isn't recognized by GDAL
*/
else if (config->rt_file_count > 1) {
drv = GDALIdentifyDriver(config->rt_file[config->rt_file_count - 1], NULL);
if (drv == NULL) {
char *ptr;
ptr = strchr(config->rt_file[config->rt_file_count - 1], '.');
/* schema.table */
if (ptr) {
config->schema = rtalloc(sizeof(char) * (ptr - config->rt_file[config->rt_file_count - 1] + 1));
if (config->schema == NULL) {
rterror(_("Could not allocate memory for storing schema name"));
rtdealloc_config(config);
exit(1);
}
snprintf(config->schema, ptr - config->rt_file[config->rt_file_count - 1] + 1, "%s", config->rt_file[config->rt_file_count - 1]);
config->schema[ptr - config->rt_file[config->rt_file_count - 1]] = '\0';
config->table = rtalloc(sizeof(char) * (strlen(config->rt_file[config->rt_file_count - 1]) - strlen(config->schema) + 1));
if (config->table == NULL) {
rterror(_("Could not allocate memory for storing table name"));
rtdealloc_config(config);
exit(1);
}
snprintf(config->table, strlen(config->rt_file[config->rt_file_count - 1]) - strlen(config->schema), "%s", ptr + 1);
config->table[strlen(config->rt_file[config->rt_file_count - 1]) - strlen(config->schema)] = '\0';
}
/* table */
else {
config->table = rtalloc(sizeof(char) * strlen(config->rt_file[config->rt_file_count - 1]) + 1);
if (config->table == NULL) {
rterror(_("Could not allocate memory for storing table name"));
rtdealloc_config(config);
exit(1);
}
strncpy(config->table, config->rt_file[config->rt_file_count - 1], strlen(config->rt_file[config->rt_file_count - 1]) + 1);
}
rtdealloc(config->rt_file[--(config->rt_file_count)]);
config->rt_file = (char **) rtrealloc(config->rt_file, sizeof(char *) * config->rt_file_count);
if (config->rt_file == NULL) {
rterror(_("Could not reallocate the memory holding raster names"));
rtdealloc_config(config);
exit(1);
}
}
}
/****************************************************************************
* validate raster files
****************************************************************************/
/* check that GDAL recognizes all files */
for (i = 0; i < config->rt_file_count; i++) {
drv = GDALIdentifyDriver(config->rt_file[i], NULL);
if (drv == NULL) {
rterror(_("Unable to read raster file: %s"), config->rt_file[i]);
rtdealloc_config(config);
exit(1);
}
}
/* process each file for just the filename */
config->rt_filename = (char **) rtalloc(sizeof(char *) * config->rt_file_count);
if (config->rt_filename == NULL) {
rterror(_("Could not allocate memory for cleaned raster filenames"));
rtdealloc_config(config);
exit(1);
}
for (i = 0; i < config->rt_file_count; i++) {
char *file;
char *ptr;
file = rtalloc(sizeof(char) * (strlen(config->rt_file[i]) + 1));
if (file == NULL) {
rterror(_("Could not allocate memory for cleaned raster filename"));
rtdealloc_config(config);
exit(1);
}
strcpy(file, config->rt_file[i]);
for (ptr = file + strlen(file); ptr > file; ptr--) {
if (*ptr == '/' || *ptr == '\\') {
ptr++;
break;
}
}
config->rt_filename[i] = rtalloc(sizeof(char) * (strlen(ptr) + 1));
if (config->rt_filename[i] == NULL) {
rterror(_("Could not allocate memory for cleaned raster filename"));
rtdealloc_config(config);
exit(1);
}
strcpy(config->rt_filename[i], ptr);
rtdealloc(file);
}
/****************************************************************************
* defaults for table and column names
****************************************************************************/
/* first file as proxy table name */
if (config->table == NULL) {
char *file;
char *ptr;
file = rtalloc(sizeof(char) * (strlen(config->rt_filename[0]) + 1));
if (file == NULL) {
rterror(_("Could not allocate memory for proxy table name"));
rtdealloc_config(config);
exit(1);
}
strcpy(file, config->rt_filename[0]);
for (ptr = file + strlen(file); ptr > file; ptr--) {
if (*ptr == '.') {
*ptr = '\0';
break;
}
}
config->table = rtalloc(sizeof(char) * (strlen(file) + 1));
if (config->table == NULL) {
rterror(_("Could not allocate memory for proxy table name"));
rtdealloc_config(config);
exit(1);
}
strcpy(config->table, file);
rtdealloc(file);
}
/* raster_column not specified, default to "rast" */
if (config->raster_column == NULL) {
config->raster_column = rtalloc(sizeof(char) * (strlen("rast") + 1));
if (config->raster_column == NULL) {
rterror(_("Could not allocate memory for default raster column name"));
rtdealloc_config(config);
exit(1);
}
strcpy(config->raster_column, "rast");
}
/* file_column_name not specified, default to "filename" */
if (config->file_column_name == NULL) {
config->file_column_name = rtalloc(sizeof(char) * (strlen("filename") + 1));
if (config->file_column_name == NULL) {
rterror(_("Could not allocate memory for default filename column name"));
rtdealloc_config(config);
exit(1);
}
strcpy(config->file_column_name, "filename");
}
/****************************************************************************
* literal PostgreSQL identifiers disabled
****************************************************************************/
/* no quotes, lower case everything */
if (!config->quoteident) {
if (config->schema != NULL)
config->schema = strtolower(config->schema);
if (config->table != NULL)
config->table = strtolower(config->table);
if (config->raster_column != NULL)
config->raster_column = strtolower(config->raster_column);
if (config->file_column_name != NULL)
config->file_column_name = strtolower(config->file_column_name);
if (config->tablespace != NULL)
config->tablespace = strtolower(config->tablespace);
if (config->idx_tablespace != NULL)
config->idx_tablespace = strtolower(config->idx_tablespace);
}
/****************************************************************************
* overview table names
****************************************************************************/
if (config->overview_count) {
char factor[4];
config->overview_table = rtalloc(sizeof(char *) * config->overview_count);
if (config->overview_table == NULL) {
rterror(_("Could not allocate memory for overview table names"));
rtdealloc_config(config);
exit(1);
}
for (i = 0; i < config->overview_count; i++) {
sprintf(factor, "%d", config->overview[i]);
config->overview_table[i] = rtalloc(sizeof(char) * (strlen("o__") + strlen(factor) + strlen(config->table) + 1));
if (config->overview_table[i] == NULL) {
rterror(_("Could not allocate memory for overview table name"));
rtdealloc_config(config);
exit(1);
}
sprintf(config->overview_table[i], "o_%d_%s", config->overview[i], config->table);
}
}
/****************************************************************************
* check that identifiers won't get truncated
****************************************************************************/
if (config->schema != NULL && strlen(config->schema) > MAXNAMELEN) {
rtwarn(_("The schema name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
config->schema,
MAXNAMELEN
);
}
if (config->table != NULL && strlen(config->table) > MAXNAMELEN) {
rtwarn(_("The table name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
config->table,
MAXNAMELEN
);
}
if (config->raster_column != NULL && strlen(config->raster_column) > MAXNAMELEN) {
rtwarn(_("The column name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
config->raster_column,
MAXNAMELEN
);
}
if (config->file_column_name != NULL && strlen(config->file_column_name) > MAXNAMELEN) {
rtwarn(_("The column name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
config->file_column_name,
MAXNAMELEN
);
}
if (config->tablespace != NULL && strlen(config->tablespace) > MAXNAMELEN) {
rtwarn(_("The tablespace name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
config->tablespace,
MAXNAMELEN
);
}
if (config->idx_tablespace != NULL && strlen(config->idx_tablespace) > MAXNAMELEN) {
rtwarn(_("The index tablespace name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
config->idx_tablespace,
MAXNAMELEN
);
}
if (config->overview_count) {
for (i = 0; i < config->overview_count; i++) {
if (strlen(config->overview_table[i]) > MAXNAMELEN) {
rtwarn(_("The overview table name \"%s\" may exceed the maximum string length permitted for PostgreSQL identifiers (%d)"),
config->overview_table[i],
MAXNAMELEN
);
}
}
}
/****************************************************************************
* double quote identifiers
****************************************************************************/
if (config->schema != NULL) {
tmp = rtalloc(sizeof(char) * (strlen(config->schema) + 4));
if (tmp == NULL) {
rterror(_("Could not allocate memory for quoting schema name"));
rtdealloc_config(config);
exit(1);
}
sprintf(tmp, "\"%s\".", config->schema);
rtdealloc(config->schema);
config->schema = tmp;
}
if (config->table != NULL) {
tmp = rtalloc(sizeof(char) * (strlen(config->table) + 3));
if (tmp == NULL) {
rterror(_("Could not allocate memory for quoting table name"));
rtdealloc_config(config);
exit(1);
}
sprintf(tmp, "\"%s\"", config->table);
rtdealloc(config->table);
config->table = tmp;
}
if (config->raster_column != NULL) {
tmp = rtalloc(sizeof(char) * (strlen(config->raster_column) + 3));
if (tmp == NULL) {
rterror(_("Could not allocate memory for quoting raster column name"));
rtdealloc_config(config);
exit(1);
}
sprintf(tmp, "\"%s\"", config->raster_column);
rtdealloc(config->raster_column);
config->raster_column = tmp;
}
if (config->file_column_name != NULL) {
tmp = rtalloc(sizeof(char) * (strlen(config->file_column_name) + 3));
if (tmp == NULL) {
rterror(_("Could not allocate memory for quoting raster column name"));
rtdealloc_config(config);
exit(1);
}
sprintf(tmp, "\"%s\"", config->file_column_name);
rtdealloc(config->file_column_name);
config->file_column_name = tmp;
}
if (config->tablespace != NULL) {
tmp = rtalloc(sizeof(char) * (strlen(config->tablespace) + 3));
if (tmp == NULL) {
rterror(_("Could not allocate memory for quoting tablespace name"));
rtdealloc_config(config);
exit(1);
}
sprintf(tmp, "\"%s\"", config->tablespace);
rtdealloc(config->tablespace);
config->tablespace = tmp;
}
if (config->idx_tablespace != NULL) {
tmp = rtalloc(sizeof(char) * (strlen(config->idx_tablespace) + 3));
if (tmp == NULL) {
rterror(_("Could not allocate memory for quoting index tablespace name"));
rtdealloc_config(config);
exit(1);
}
sprintf(tmp, "\"%s\"", config->idx_tablespace);
rtdealloc(config->idx_tablespace);
config->idx_tablespace = tmp;
}
if (config->overview_count) {
for (i = 0; i < config->overview_count; i++) {
tmp = rtalloc(sizeof(char) * (strlen(config->overview_table[i]) + 3));
if (tmp == NULL) {
rterror(_("Could not allocate memory for quoting overview table name"));
rtdealloc_config(config);
exit(1);
}
sprintf(tmp, "\"%s\"", config->overview_table[i]);
rtdealloc(config->overview_table[i]);
config->overview_table[i] = tmp;
}
}
/****************************************************************************
* processing of rasters
****************************************************************************/
/* initialize string buffer */
buffer = rtalloc(sizeof(STRINGBUFFER));
if (buffer == NULL) {
rterror(_("Could not allocate memory for output string buffer"));
rtdealloc_config(config);
exit(1);
}
init_stringbuffer(buffer);
/* pass off to processing function */
if (!process_rasters(config, buffer)) {
rterror(_("Unable to process rasters"));
rtdealloc_stringbuffer(buffer, 1);
rtdealloc_config(config);
exit(1);
}
flush_stringbuffer(buffer);
rtdealloc_stringbuffer(buffer, 1);
rtdealloc_config(config);
return 0;
}