From: Bborie Park Date: Wed, 14 Dec 2011 01:22:54 +0000 (+0000) Subject: Refactored for less memory usage by aggresively flushing string buffers. X-Git-Tag: 2.0.0alpha1~475 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f69eaab85aa58b5d24291ddfec2328a75a96f6dc;p=postgis Refactored for less memory usage by aggresively flushing string buffers. git-svn-id: http://svn.osgeo.org/postgis/trunk@8398 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/raster/loader/raster2pgsql.c b/raster/loader/raster2pgsql.c index 6f8b74b77..c11f7f925 100644 --- a/raster/loader/raster2pgsql.c +++ b/raster/loader/raster2pgsql.c @@ -511,894 +511,959 @@ append_stringbuffer(STRINGBUFFER *buffer, const char *str) { } static int -build_overviews(int idx, RTLOADERCFG *config, RASTERINFO *info, STRINGBUFFER *ovset) { - GDALDatasetH hdsSrc; - VRTDatasetH hdsOv; - VRTSourcedRasterBandH hbandOv; - double gtOv[6] = {0.}; - int dimOv[2] = {0}; - int factor = 0; +append_sql_to_buffer(STRINGBUFFER *buffer, const char *str) { + if (buffer->length > 9) + flush_stringbuffer(buffer); - int i = 0; - int j = 0; + return append_stringbuffer(buffer, str); +} - VRTDatasetH hdsDst; - VRTSourcedRasterBandH hbandDst; - int tile_size[2] = {0}; - int ntiles[2] = {1, 1}; - int xtile = 0; - int ytile = 0; - double gt[6] = {0.}; +static int +insert_records( + const char *schema, const char *table, const char *column, + const char *filename, int copy_statements, + STRINGBUFFER *tileset, STRINGBUFFER *buffer +) { + char *fn = NULL; + uint32_t len = 0; + char *sql = NULL; + uint32_t x = 0; - rt_raster rast = NULL; - char *hex; - uint32_t hexlen = 0; + assert(table != NULL); + assert(column != NULL); - hdsSrc = GDALOpenShared(config->rt_file[idx], GA_ReadOnly); - if (hdsSrc == NULL) { - fprintf(stderr, _("Cannot open raster: %s\n"), config->rt_file[idx]); - return 0; - } + /* COPY statements */ + if (copy_statements) { - /* working copy of geotransform matrix */ - memcpy(gtOv, info->gt, sizeof(double) * 6); + /* escape tabs in filename */ + if (filename != NULL) + fn = strreplace(filename, "\t", "\\t", NULL); - /* loop over each overview factor */ - for (i = 0; i < config->overview_count; i++) { - factor = config->overview[i]; - if (factor < 2) continue; - - 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 - ); - } + /* rows */ + for (x = 0; x < tileset->length; x++) { + len = strlen(tileset->line[x]) + 1; - /* make sure VRT reflects all changes */ - VRTFlushCache(hdsOv); + if (filename != NULL) + len += strlen(fn) + 1; - /* 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]; + sql = rtalloc(sizeof(char) * len); + if (sql == NULL) { + fprintf(stderr, _("Could not allocate memory for COPY statement\n")); + return 0; + } + sprintf(sql, "%s%s%s", + tileset->line[x], + (filename != NULL ? "\t" : ""), + (filename != NULL ? fn : "") + ); - /* 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]; + append_sql_to_buffer(buffer, sql); + rtdealloc(sql); + sql = NULL; } - /* working copy of geotransform matrix */ - memcpy(gt, gtOv, sizeof(double) * 6); + } + /* INSERT statements */ + else { + len = strlen("INSERT INTO () VALUES (''::raster);") + 1; + if (schema != NULL) + len += strlen(schema); + len += strlen(table); + len += strlen(column); + if (filename != NULL) + len += strlen(",\"filename\""); - /* 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++) { - for (xtile = 0; xtile < ntiles[0]; xtile++) { - /* - char fn[100]; - sprintf(fn, "/tmp/tile%d.vrt", (ytile * ntiles[0]) + xtile); - */ + /* escape single-quotes in filename */ + if (filename != NULL) + fn = strreplace(filename, "'", "''", NULL); - /* compute tile's upper-left corner */ - GDALApplyGeoTransform( - gtOv, - xtile * tile_size[0], ytile * tile_size[1], - &(gt[0]), &(gt[3]) - ); + for (x = 0; x < tileset->length; x++) { + int sqllen = len; - /* create VRT dataset */ - hdsDst = VRTCreate(tile_size[0], tile_size[1]); - /* - GDALSetDescription(hdsDst, fn); - */ - GDALSetProjection(hdsDst, info->srs); - GDALSetGeoTransform(hdsDst, gt); + sqllen += strlen(tileset->line[x]); + if (filename != NULL) + sqllen += strlen(",''") + strlen(fn); - /* 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); + sql = rtalloc(sizeof(char) * sqllen); + if (sql == NULL) { + fprintf(stderr, _("Could not allocate memory for INSERT statement\n")); + return 0; + } + sprintf(sql, "INSERT INTO %s%s (%s%s) VALUES ('%s'::raster%s%s%s);", + (schema != NULL ? schema : ""), + table, + column, + (filename != NULL ? ",\"filename\"" : ""), + tileset->line[x], + (filename != NULL ? ",'" : ""), + (filename != NULL ? fn : ""), + (filename != NULL ? "'" : "") + ); - if (info->hasnodata[j]) - GDALSetRasterNoDataValue(hbandDst, info->nodataval[j]); + append_sql_to_buffer(buffer, sql); + rtdealloc(sql); + sql = NULL; + } + } - 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 - ); - } + if (fn != NULL) rtdealloc(fn); + return 1; +} - /* make sure VRT reflects all changes */ - VRTFlushCache(hdsDst); +static int +drop_table(const char *schema, const char *table, STRINGBUFFER *buffer) { + char *sql = NULL; + uint32_t len = 0; - /* convert VRT dataset to rt_raster */ - rast = rt_raster_from_gdal_dataset(hdsDst); + len = strlen("DROP TABLE IF EXISTS ;") + 1; + if (schema != NULL) + len += strlen(schema); + len += strlen(table); - /* set srid if provided */ - rt_raster_set_srid(rast, config->srid); + sql = rtalloc(sizeof(char) * len); + if (sql == NULL) { + fprintf(stderr, _("Could not allocate memory for DROP TABLE statement\n")); + return 0; + } + sprintf(sql, "DROP TABLE IF EXISTS %s%s;", + (schema != NULL ? schema : ""), + table + ); - /* convert rt_raster to hexwkb */ - hex = rt_raster_to_hexwkb(rast, &hexlen); - raster_destroy(rast); + append_sql_to_buffer(buffer, sql); + rtdealloc(sql); - /* add hexwkb to tileset */ - append_stringbuffer(&(ovset[i]), hex); + return 1; +} - rtdealloc(hex); - GDALClose(hdsDst); - } - } +static int +create_table( + const char *schema, const char *table, const char *column, + const int file_column, + 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(",\"filename\" text"); + if (tablespace != NULL) + len += strlen(" TABLESPACE ") + strlen(tablespace); + if (idx_tablespace != NULL) + len += strlen(" USING INDEX TABLESPACE ") + strlen(idx_tablespace); - GDALClose(hdsOv); + sql = rtalloc(sizeof(char) * len); + if (sql == NULL) { + fprintf(stderr, _("Could not allocate memory for CREATE TABLE statement\n")); + return 0; } + sprintf(sql, "CREATE TABLE %s%s (\"rid\" serial PRIMARY KEY,%s raster%s)%s%s%s%s;", + (schema != NULL ? schema : ""), + table, + column, + (file_column ? ",\"filename\" text" : ""), + (tablespace != NULL ? " TABLESPACE " : ""), + (tablespace != NULL ? tablespace : ""), + (idx_tablespace != NULL ? " USING INDEX TABLESPACE " : ""), + (idx_tablespace != NULL ? idx_tablespace : "") + ); + + append_sql_to_buffer(buffer, sql); + rtdealloc(sql); - GDALClose(hdsSrc); return 1; } static int -convert_raster(int idx, RTLOADERCFG *config, RASTERINFO *info, STRINGBUFFER *tileset) { - GDALDatasetH hdsSrc; - GDALRasterBandH hbandSrc; - int nband = 0; - int i = 0; - int ntiles[2] = {1, 1}; - int xtile = 0; - int ytile = 0; - double gt[6] = {0.}; +copy_from( + const char *schema, const char *table, const char *column, + const char *filename, + STRINGBUFFER *buffer +) { + char *sql = NULL; + uint32_t len = 0; - rt_raster rast = NULL; - char *hex; - uint32_t hexlen = 0; + assert(table != NULL); + assert(column != NULL); - hdsSrc = GDALOpenShared(config->rt_file[idx], GA_ReadOnly); - if (hdsSrc == NULL) { - fprintf(stderr, _("Cannot open raster: %s\n"), config->rt_file[idx]); - return 0; - } + len = strlen("COPY () FROM stdin;") + 1; + if (schema != NULL) + len += strlen(schema); + len += strlen(table); + len += strlen(column); + if (filename != NULL) + len += strlen(",\"filename\""); - nband = GDALGetRasterCount(hdsSrc); - if (!nband) { - fprintf(stderr, _("No bands found in raster: %s\n"), config->rt_file[idx]); - GDALClose(hdsSrc); + sql = rtalloc(sizeof(char) * len); + if (sql == NULL) { + fprintf(stderr, _("Could not allocate memory for COPY statement\n")); return 0; } + sprintf(sql, "COPY %s%s (%s%s) FROM stdin;", + (schema != NULL ? schema : ""), + table, + column, + (filename != NULL ? ",\"filename\"" : "") + ); - /* check that bands specified are available */ - for (i = 0; i < config->nband_count; i++) { - if (config->nband[i] > nband) { - fprintf(stderr, _("Band %d not found in raster: %s\n"), config->nband[i], config->rt_file[idx]); - GDALClose(hdsSrc); - return 0; - } - } + append_sql_to_buffer(buffer, sql); + rtdealloc(sql); + sql = NULL; - /* record srs */ - if (GDALGetProjectionRef(hdsSrc) != NULL) { - info->srs = rtalloc(sizeof(char) * (strlen(GDALGetProjectionRef(hdsSrc)) + 1)); - if (info->srs == NULL) { - fprintf(stderr, _("Could not allocate memory for storing SRS\n")); - GDALClose(hdsSrc); - return 0; - } - strcpy(info->srs, GDALGetProjectionRef(hdsSrc)); - } + return 1; +} - /* record geotransform matrix */ - if (GDALGetGeoTransform(hdsSrc, info->gt) != CE_None) { - fprintf(stderr, _("Cannot get geotransform matrix from raster: %s\n"), config->rt_file[idx]); - GDALClose(hdsSrc); - return 0; - } - memcpy(gt, info->gt, sizeof(double) * 6); +static int +copy_from_end(STRINGBUFFER *buffer) { + /* end of data */ + append_sql_to_buffer(buffer, "\\."); - /* 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) { - fprintf(stderr, _("Could not allocate memory for storing band indices\n")); - 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) { - fprintf(stderr, _("Could not allocate memory for storing band indices\n")); - GDALClose(hdsSrc); - return 0; - } - for (i = 0; i < info->nband_count; i++) - info->nband[i] = i + 1; - } + return 1; +} - /* initialize parameters dependent on nband */ - info->gdalbandtype = rtalloc(sizeof(GDALDataType) * info->nband_count); - if (info->gdalbandtype == NULL) { - fprintf(stderr, _("Could not allocate memory for storing GDAL data type\n")); - GDALClose(hdsSrc); - return 0; - } - info->bandtype = rtalloc(sizeof(rt_pixtype) * info->nband_count); - if (info->bandtype == NULL) { - fprintf(stderr, _("Could not allocate memory for storing pixel type\n")); - GDALClose(hdsSrc); - return 0; - } - info->hasnodata = rtalloc(sizeof(int) * info->nband_count); - if (info->hasnodata == NULL) { - fprintf(stderr, _("Could not allocate memory for storing hasnodata flag\n")); - GDALClose(hdsSrc); - return 0; - } - info->nodataval = rtalloc(sizeof(double) * info->nband_count); - if (info->nodataval == NULL) { - fprintf(stderr, _("Could not allocate memory for storing nodata value\n")); - 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); +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; - /* dimensions of raster */ - info->dim[0] = GDALGetRasterXSize(hdsSrc); - info->dim[1] = GDALGetRasterYSize(hdsSrc); + assert(table != NULL); + assert(column != NULL); - /* 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]; + /* create index */ + len = strlen("CREATE INDEX ON USING gist (st_convexhull());") + 1; + if (schema != NULL) + len += strlen(schema); + len += strlen(table); + len += strlen(column); + if (tablespace != NULL) + len += strlen(" TABLESPACE ") + strlen(tablespace); - /* number of tiles */ - if ( - info->tile_size[0] != info->dim[0] && - info->tile_size[1] != info->dim[1] - ) { - ntiles[0] = (info->dim[0] + info->tile_size[0] - 1) / info->tile_size[0]; - ntiles[1] = (info->dim[1] + info->tile_size[1] - 1) / info->tile_size[1]; + sql = rtalloc(sizeof(char) * len); + if (sql == NULL) { + fprintf(stderr, _("Could not allocate memory for CREATE INDEX statement\n")); + 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 : "") + ); - /* go through bands for attributes */ - for (i = 0; i < info->nband_count; i++) { - hbandSrc = GDALGetRasterBand(hdsSrc, info->nband[i]); + append_sql_to_buffer(buffer, sql); + rtdealloc(sql); - /* datatype */ - info->gdalbandtype[i] = GDALGetRasterDataType(hbandSrc); + return 1; +} - /* complex data type? */ - if (GDALDataTypeIsComplex(info->gdalbandtype[i])) { - fprintf(stderr, _("The pixel type of band %d is a complex data type. PostGIS Raster does not support complex data types\n"), i + 1); - GDALClose(hdsSrc); - return 0; - } +static int +analyze_table( + const char *schema, const char *table, + STRINGBUFFER *buffer +) { + char *sql = NULL; + uint32_t len = 0; - /* convert data type to that of postgis raster */ - info->bandtype[i] = rt_util_gdal_datatype_to_pixtype(info->gdalbandtype[i]); + assert(table != NULL); - /* 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; - } + len = strlen("ANALYZE ;") + 1; + if (schema != NULL) + len += strlen(schema); + len += strlen(table); + + sql = rtalloc(sizeof(char) * len); + if (sql == NULL) { + fprintf(stderr, _("Could not allocate memory for ANALYZE TABLE statement\n")); + return 0; } + sprintf(sql, "ANALYZE %s%s;", + (schema != NULL ? schema : ""), + table + ); - /* out-db raster */ - if (config->outdb) { - rt_band band = NULL; + append_sql_to_buffer(buffer, sql); + rtdealloc(sql); - GDALClose(hdsSrc); + return 1; +} - /* each tile is a raster */ - for (ytile = 0; ytile < ntiles[1]; ytile++) { - for (xtile = 0; xtile < ntiles[0]; xtile++) { - - /* compute tile's upper-left corner */ - GDALApplyGeoTransform( - info->gt, - xtile * info->tile_size[0], ytile * info->tile_size[1], - &(gt[0]), &(gt[3]) - ); +static int +vacuum_table( + const char *schema, const char *table, + STRINGBUFFER *buffer +) { + char *sql = NULL; + uint32_t len = 0; - /* create raster object */ - rast = rt_raster_new(info->tile_size[0], info->tile_size[1]); - if (rast == NULL) { - fprintf(stderr, _("Could not create raster\n")); - return 0; - } + assert(table != NULL); - /* set raster attributes */ - rt_raster_set_srid(rast, config->srid); - rt_raster_set_geotransform_matrix(rast, gt); + len = strlen("VACUUM ANALYZE ;") + 1; + if (schema != NULL) + len += strlen(schema); + len += strlen(table); - /* add bands */ - for (i = 0; i < info->nband_count; i++) { - band = rt_band_new_offline( - info->tile_size[0], info->tile_size[1], - info->bandtype[i], - info->hasnodata[i], info->nodataval[i], - info->nband[i] - 1, - config->rt_file[idx] - ); - if (band == NULL) { - fprintf(stderr, _("Could not create offline band\n")); - raster_destroy(rast); - return 0; - } + sql = rtalloc(sizeof(char) * len); + if (sql == NULL) { + fprintf(stderr, _("Could not allocate memory for VACUUM statement\n")); + return 0; + } + sprintf(sql, "VACUUM ANALYZE %s%s;", + (schema != NULL ? schema : ""), + table + ); - /* add band to raster */ - if (rt_raster_add_band(rast, band, rt_raster_get_num_bands(rast)) == -1) { - fprintf(stderr, _("Could not add offlineband to raster\n")); - rt_band_destroy(band); - raster_destroy(rast); - return 0; - } - } + append_sql_to_buffer(buffer, sql); + rtdealloc(sql); - /* convert rt_raster to hexwkb */ - hex = rt_raster_to_hexwkb(rast, &hexlen); - raster_destroy(rast); + return 1; +} - /* add hexwkb to tileset */ - append_stringbuffer(tileset, hex); +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; - rtdealloc(hex); - } - } - } - /* in-db raster */ - else { - VRTDatasetH hdsDst; - VRTSourcedRasterBandH hbandDst; + char *_schema = NULL; + char *_table = NULL; + char *_column = NULL; - /* each tile is a VRT with constraints set for just the data required for the tile */ - for (ytile = 0; ytile < ntiles[1]; ytile++) { - for (xtile = 0; xtile < ntiles[0]; xtile++) { + assert(table != NULL); + assert(column != NULL); - /* compute tile's upper-left corner */ - GDALApplyGeoTransform( - info->gt, - xtile * info->tile_size[0], ytile * info->tile_size[1], - &(gt[0]), &(gt[3]) - ); + if (schema != NULL) { + char *tmp = chartrim(schema, "."); + _schema = chartrim(tmp, "\""); + rtdealloc(tmp); + } + _table = chartrim(table, "\""); + _column = chartrim(column, "\""); - /* create VRT dataset */ - hdsDst = VRTCreate(info->tile_size[0], info->tile_size[1]); - GDALSetProjection(hdsDst, info->srs); - GDALSetGeoTransform(hdsDst, gt); + len = strlen("SELECT AddRasterConstraints('','','',TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE);") + 1; + if (_schema != NULL) + len += strlen(_schema); + len += strlen(_table); + len += strlen(_column); - /* 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); + sql = rtalloc(sizeof(char) * len); + if (sql == NULL) { + fprintf(stderr, _("Could not allocate memory for AddRasterConstraints statement\n")); + return 0; + } + sprintf(sql, "SELECT AddRasterConstraints('%s','%s','%s',TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,%s,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); - if (info->hasnodata[i]) - GDALSetRasterNoDataValue(hbandDst, info->nodataval[i]); + append_sql_to_buffer(buffer, sql); + rtdealloc(sql); - VRTAddSimpleSource( - hbandDst, GDALGetRasterBand(hdsSrc, info->nband[i]), - xtile * info->tile_size[0], ytile * info->tile_size[1], - info->tile_size[0], info->tile_size[1], - 0, 0, - info->tile_size[0], info->tile_size[1], - "near", VRT_NODATA_UNSET - ); - } + return 1; +} - /* make sure VRT reflects all changes */ - VRTFlushCache(hdsDst); +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; - /* convert VRT dataset to rt_raster */ - rast = rt_raster_from_gdal_dataset(hdsDst); + char *_ovschema = NULL; + char *_ovtable = NULL; + char *_ovcolumn = NULL; - /* set srid if provided */ - rt_raster_set_srid(rast, config->srid); + char *_schema = NULL; + char *_table = NULL; + char *_column = NULL; - /* convert rt_raster to hexwkb */ - hex = rt_raster_to_hexwkb(rast, &hexlen); - raster_destroy(rast); + assert(ovtable != NULL); + assert(ovcolumn != NULL); + assert(table != NULL); + assert(column != NULL); + assert(factor >= MINOVFACTOR && factor <= MAXOVFACTOR); - /* add hexwkb to tileset */ - append_stringbuffer(tileset, hex); + if (ovschema != NULL) { + char *tmp = chartrim(ovschema, "."); + _ovschema = chartrim(tmp, "\""); + rtdealloc(tmp); + } + _ovtable = chartrim(ovtable, "\""); + _ovcolumn = chartrim(ovcolumn, "\""); - rtdealloc(hex); - GDALClose(hdsDst); - } - } + if (schema != NULL) { + char *tmp = chartrim(schema, "."); + _schema = chartrim(tmp, "\""); + rtdealloc(tmp); + } + _table = chartrim(table, "\""); + _column = chartrim(column, "\""); - GDALClose(hdsSrc); + 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) { + fprintf(stderr, _("Could not allocate memory for AddOverviewConstraints statement\n")); + 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); + rtdealloc(sql); return 1; } static int -insert_records( - const char *schema, const char *table, const char *column, - const char *filename, int copy_statements, - STRINGBUFFER *tileset, STRINGBUFFER *buffer -) { - char *fn = NULL; - uint32_t len = 0; - char *sql = NULL; - uint32_t x = 0; +build_overview(int idx, RTLOADERCFG *config, RASTERINFO *info, int factor, STRINGBUFFER *tileset, STRINGBUFFER *buffer) { + GDALDatasetH hdsSrc; + VRTDatasetH hdsOv; + VRTSourcedRasterBandH hbandOv; + double gtOv[6] = {0.}; + int dimOv[2] = {0}; - assert(table != NULL); - assert(column != NULL); + int j = 0; - append_stringbuffer(buffer, ""); + VRTDatasetH hdsDst; + VRTSourcedRasterBandH hbandDst; + int tile_size[2] = {0}; + int ntiles[2] = {1, 1}; + int xtile = 0; + int ytile = 0; + double gt[6] = {0.}; - /* COPY statements */ - if (copy_statements) { + rt_raster rast = NULL; + char *hex; + uint32_t hexlen = 0; - /* COPY */ - len = strlen("COPY () FROM stdin;") + 1; - if (schema != NULL) - len += strlen(schema); - len += strlen(table); - len += strlen(column); - if (filename != NULL) - len += strlen(",\"filename\""); + hdsSrc = GDALOpenShared(config->rt_file[idx], GA_ReadOnly); + if (hdsSrc == NULL) { + fprintf(stderr, _("Cannot open raster: %s\n"), config->rt_file[idx]); + return 0; + } - sql = rtalloc(sizeof(char) * len); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for COPY statement\n")); - return 0; - } - sprintf(sql, "COPY %s%s (%s%s) FROM stdin;", - (schema != NULL ? schema : ""), - table, - column, - (filename != NULL ? ",\"filename\"" : "") - ); + /* working copy of geotransform matrix */ + memcpy(gtOv, info->gt, sizeof(double) * 6); - append_stringbuffer(buffer, sql); - rtdealloc(sql); - sql = NULL; + /* loop over each overview factor */ + if (factor < MINOVFACTOR || factor > MAXOVFACTOR) { + fprintf(stderr, _("Overview factor %d is not between %d and %d\n"), factor, MINOVFACTOR, MAXOVFACTOR); + return 0; + } - /* escape tabs in filename */ - if (filename != NULL) - fn = strreplace(filename, "\t", "\\t", NULL); + dimOv[0] = (int) (info->dim[0] + (factor / 2)) / factor; + dimOv[1] = (int) (info->dim[1] + (factor / 2)) / factor; - /* rows */ - for (x = 0; x < tileset->length; x++) { - len = strlen(tileset->line[x]) + 1; + /* create VRT dataset */ + hdsOv = VRTCreate(dimOv[0], dimOv[1]); + /* + GDALSetDescription(hdsOv, "/tmp/ov.vrt"); + */ + GDALSetProjection(hdsOv, info->srs); - if (filename != NULL) - len += strlen(fn) + 1; + /* adjust scale */ + gtOv[1] *= factor; + gtOv[5] *= factor; - sql = rtalloc(sizeof(char) * len); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for COPY statement\n")); - return 0; - } - sprintf(sql, "%s%s%s", - tileset->line[x], - (filename != NULL ? "\t" : ""), - (filename != NULL ? fn : "") - ); + GDALSetGeoTransform(hdsOv, gtOv); - append_stringbuffer(buffer, sql); - rtdealloc(sql); - sql = NULL; - } + /* 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]); - /* end of data */ - append_stringbuffer(buffer, "\\."); + 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 + ); } - /* INSERT statements */ - else { - len = strlen("INSERT INTO () VALUES (''::raster);") + 1; - if (schema != NULL) - len += strlen(schema); - len += strlen(table); - len += strlen(column); - if (filename != NULL) - len += strlen(",\"filename\""); - /* escape single-quotes in filename */ - if (filename != NULL) - fn = strreplace(filename, "'", "''", NULL); + /* make sure VRT reflects all changes */ + VRTFlushCache(hdsOv); - for (x = 0; x < tileset->length; x++) { - int sqllen = len; + /* 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]; - sqllen += strlen(tileset->line[x]); - if (filename != NULL) - sqllen += strlen(",''") + strlen(fn); + /* 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]; + } - sql = rtalloc(sizeof(char) * sqllen); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for INSERT statement\n")); - return 0; - } - sprintf(sql, "INSERT INTO %s%s (%s%s) VALUES ('%s'::raster%s%s%s);", - (schema != NULL ? schema : ""), - table, - column, - (filename != NULL ? ",\"filename\"" : ""), - tileset->line[x], - (filename != NULL ? ",'" : ""), - (filename != NULL ? fn : ""), - (filename != NULL ? "'" : "") + /* 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++) { + for (xtile = 0; xtile < ntiles[0]; xtile++) { + /* + char fn[100]; + sprintf(fn, "/tmp/tile%d.vrt", (ytile * ntiles[0]) + xtile); + */ + + /* compute tile's upper-left corner */ + GDALApplyGeoTransform( + gtOv, + xtile * tile_size[0], ytile * tile_size[1], + &(gt[0]), &(gt[3]) ); - append_stringbuffer(buffer, sql); - rtdealloc(sql); - sql = NULL; - } - } + /* create VRT dataset */ + hdsDst = VRTCreate(tile_size[0], tile_size[1]); + /* + GDALSetDescription(hdsDst, fn); + */ + GDALSetProjection(hdsDst, info->srs); + GDALSetGeoTransform(hdsDst, gt); - append_stringbuffer(buffer, ""); + /* 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 (fn != NULL) rtdealloc(fn); - return 1; -} + if (info->hasnodata[j]) + GDALSetRasterNoDataValue(hbandDst, info->nodataval[j]); -static int -drop_table(const char *schema, const char *table, STRINGBUFFER *buffer) { - char *sql = NULL; - uint32_t len = 0; + 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 + ); + } - len = strlen("DROP TABLE IF EXISTS ;") + 1; - if (schema != NULL) - len += strlen(schema); - len += strlen(table); + /* make sure VRT reflects all changes */ + VRTFlushCache(hdsDst); - sql = rtalloc(sizeof(char) * len); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for DROP TABLE statement\n")); - return 0; - } - sprintf(sql, "DROP TABLE IF EXISTS %s%s;", - (schema != NULL ? schema : ""), - table - ); + /* convert VRT dataset to rt_raster */ + rast = rt_raster_from_gdal_dataset(hdsDst); - append_stringbuffer(buffer, sql); - rtdealloc(sql); + /* set srid if provided */ + rt_raster_set_srid(rast, config->srid); - return 1; -} + /* convert rt_raster to hexwkb */ + hex = rt_raster_to_hexwkb(rast, &hexlen); + raster_destroy(rast); -static int -create_table( - const char *schema, const char *table, const char *column, - const int file_column, - const char *tablespace, const char *idx_tablespace, - STRINGBUFFER *buffer -) { - char *sql = NULL; - uint32_t len = 0; + /* add hexwkb to tileset */ + append_stringbuffer(tileset, hex); + + rtdealloc(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->copy_statements, + tileset, buffer + )) { + fprintf(stderr, _("Cannot convert raster tiles into INSERT or COPY statements\n")); + GDALClose(hdsSrc); + return 0; + } + + rtdealloc_stringbuffer(tileset, 0); + } + } + } - assert(table != NULL); - assert(column != NULL); + GDALClose(hdsOv); + GDALClose(hdsSrc); + return 1; +} - 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(",\"filename\" text"); - if (tablespace != NULL) - len += strlen(" TABLESPACE ") + strlen(tablespace); - if (idx_tablespace != NULL) - len += strlen(" USING INDEX TABLESPACE ") + strlen(idx_tablespace); +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 xtile = 0; + int ytile = 0; + double gt[6] = {0.}; - sql = rtalloc(sizeof(char) * len); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for CREATE TABLE statement\n")); + rt_raster rast = NULL; + char *hex; + uint32_t hexlen = 0; + + hdsSrc = GDALOpenShared(config->rt_file[idx], GA_ReadOnly); + if (hdsSrc == NULL) { + fprintf(stderr, _("Cannot open raster: %s\n"), config->rt_file[idx]); return 0; } - sprintf(sql, "CREATE TABLE %s%s (\"rid\" serial PRIMARY KEY,%s raster%s)%s%s%s%s;", - (schema != NULL ? schema : ""), - table, - column, - (file_column ? ",\"filename\" text" : ""), - (tablespace != NULL ? " TABLESPACE " : ""), - (tablespace != NULL ? tablespace : ""), - (idx_tablespace != NULL ? " USING INDEX TABLESPACE " : ""), - (idx_tablespace != NULL ? idx_tablespace : "") - ); - append_stringbuffer(buffer, sql); - rtdealloc(sql); + nband = GDALGetRasterCount(hdsSrc); + if (!nband) { + fprintf(stderr, _("No bands found in raster: %s\n"), config->rt_file[idx]); + GDALClose(hdsSrc); + return 0; + } - return 1; -} + /* check that bands specified are available */ + for (i = 0; i < config->nband_count; i++) { + if (config->nband[i] > nband) { + fprintf(stderr, _("Band %d not found in raster: %s\n"), config->nband[i], config->rt_file[idx]); + GDALClose(hdsSrc); + return 0; + } + } -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; + /* record srs */ + if (GDALGetProjectionRef(hdsSrc) != NULL) { + info->srs = rtalloc(sizeof(char) * (strlen(GDALGetProjectionRef(hdsSrc)) + 1)); + if (info->srs == NULL) { + fprintf(stderr, _("Could not allocate memory for storing SRS\n")); + GDALClose(hdsSrc); + return 0; + } + strcpy(info->srs, GDALGetProjectionRef(hdsSrc)); + } - assert(table != NULL); - assert(column != NULL); + /* record geotransform matrix */ + if (GDALGetGeoTransform(hdsSrc, info->gt) != CE_None) { + fprintf(stderr, _("Cannot get geotransform matrix from raster: %s\n"), config->rt_file[idx]); + GDALClose(hdsSrc); + return 0; + } + memcpy(gt, info->gt, sizeof(double) * 6); - /* create index */ - len = strlen("CREATE INDEX ON USING gist (st_convexhull());") + 1; - if (schema != NULL) - len += strlen(schema); - len += strlen(table); - len += strlen(column); - if (tablespace != NULL) - len += strlen(" TABLESPACE ") + strlen(tablespace); + /* 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) { + fprintf(stderr, _("Could not allocate memory for storing band indices\n")); + 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) { + fprintf(stderr, _("Could not allocate memory for storing band indices\n")); + GDALClose(hdsSrc); + return 0; + } + for (i = 0; i < info->nband_count; i++) + info->nband[i] = i + 1; + } - sql = rtalloc(sizeof(char) * len); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for CREATE INDEX statement\n")); + /* initialize parameters dependent on nband */ + info->gdalbandtype = rtalloc(sizeof(GDALDataType) * info->nband_count); + if (info->gdalbandtype == NULL) { + fprintf(stderr, _("Could not allocate memory for storing GDAL data type\n")); + GDALClose(hdsSrc); 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 : "") - ); + info->bandtype = rtalloc(sizeof(rt_pixtype) * info->nband_count); + if (info->bandtype == NULL) { + fprintf(stderr, _("Could not allocate memory for storing pixel type\n")); + GDALClose(hdsSrc); + return 0; + } + info->hasnodata = rtalloc(sizeof(int) * info->nband_count); + if (info->hasnodata == NULL) { + fprintf(stderr, _("Could not allocate memory for storing hasnodata flag\n")); + GDALClose(hdsSrc); + return 0; + } + info->nodataval = rtalloc(sizeof(double) * info->nband_count); + if (info->nodataval == NULL) { + fprintf(stderr, _("Could not allocate memory for storing nodata value\n")); + 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); - append_stringbuffer(buffer, sql); - rtdealloc(sql); + /* dimensions of raster */ + info->dim[0] = GDALGetRasterXSize(hdsSrc); + info->dim[1] = GDALGetRasterYSize(hdsSrc); - return 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]; -static int -analyze_table( - const char *schema, const char *table, - STRINGBUFFER *buffer -) { - char *sql = NULL; - uint32_t len = 0; + /* number of tiles */ + if ( + info->tile_size[0] != info->dim[0] && + info->tile_size[1] != info->dim[1] + ) { + ntiles[0] = (info->dim[0] + info->tile_size[0] - 1) / info->tile_size[0]; + ntiles[1] = (info->dim[1] + info->tile_size[1] - 1) / info->tile_size[1]; + } - assert(table != NULL); + /* go through bands for attributes */ + for (i = 0; i < info->nband_count; i++) { + hbandSrc = GDALGetRasterBand(hdsSrc, info->nband[i]); - len = strlen("ANALYZE ;") + 1; - if (schema != NULL) - len += strlen(schema); - len += strlen(table); + /* datatype */ + info->gdalbandtype[i] = GDALGetRasterDataType(hbandSrc); - sql = rtalloc(sizeof(char) * len); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for ANALYZE TABLE statement\n")); - return 0; + /* complex data type? */ + if (GDALDataTypeIsComplex(info->gdalbandtype[i])) { + fprintf(stderr, _("The pixel type of band %d is a complex data type. PostGIS Raster does not support complex data types\n"), 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; + } } - sprintf(sql, "ANALYZE %s%s;", - (schema != NULL ? schema : ""), - table - ); - append_stringbuffer(buffer, sql); - rtdealloc(sql); + /* out-db raster */ + if (config->outdb) { + rt_band band = NULL; - return 1; -} + GDALClose(hdsSrc); -static int -vacuum_table( - const char *schema, const char *table, - STRINGBUFFER *buffer -) { - char *sql = NULL; - uint32_t len = 0; + /* each tile is a raster */ + for (ytile = 0; ytile < ntiles[1]; ytile++) { + for (xtile = 0; xtile < ntiles[0]; xtile++) { + + /* compute tile's upper-left corner */ + GDALApplyGeoTransform( + info->gt, + xtile * info->tile_size[0], ytile * info->tile_size[1], + &(gt[0]), &(gt[3]) + ); - assert(table != NULL); + /* create raster object */ + rast = rt_raster_new(info->tile_size[0], info->tile_size[1]); + if (rast == NULL) { + fprintf(stderr, _("Could not create raster\n")); + return 0; + } - len = strlen("VACUUM ANALYZE ;") + 1; - if (schema != NULL) - len += strlen(schema); - len += strlen(table); + /* set raster attributes */ + rt_raster_set_srid(rast, config->srid); + rt_raster_set_geotransform_matrix(rast, gt); - sql = rtalloc(sizeof(char) * len); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for VACUUM statement\n")); - return 0; - } - sprintf(sql, "VACUUM ANALYZE %s%s;", - (schema != NULL ? schema : ""), - table - ); + /* add bands */ + for (i = 0; i < info->nband_count; i++) { + band = rt_band_new_offline( + info->tile_size[0], info->tile_size[1], + info->bandtype[i], + info->hasnodata[i], info->nodataval[i], + info->nband[i] - 1, + config->rt_file[idx] + ); + if (band == NULL) { + fprintf(stderr, _("Could not create offline band\n")); + raster_destroy(rast); + return 0; + } - append_stringbuffer(buffer, sql); - rtdealloc(sql); + /* add band to raster */ + if (rt_raster_add_band(rast, band, rt_raster_get_num_bands(rast)) == -1) { + fprintf(stderr, _("Could not add offlineband to raster\n")); + rt_band_destroy(band); + raster_destroy(rast); + return 0; + } + } - return 1; -} + /* convert rt_raster to hexwkb */ + hex = rt_raster_to_hexwkb(rast, &hexlen); + raster_destroy(rast); -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; + /* add hexwkb to tileset */ + append_stringbuffer(tileset, hex); - char *_schema = NULL; - char *_table = NULL; - char *_column = NULL; + rtdealloc(hex); - assert(table != NULL); - assert(column != NULL); + /* 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->copy_statements, + tileset, buffer + )) { + fprintf(stderr, _("Cannot convert raster tiles into INSERT or COPY statements\n")); + return 0; + } - if (schema != NULL) { - char *tmp = chartrim(schema, "."); - _schema = chartrim(tmp, "\""); - rtdealloc(tmp); + rtdealloc_stringbuffer(tileset, 0); + } + } + } } - _table = chartrim(table, "\""); - _column = chartrim(column, "\""); + /* in-db raster */ + else { + VRTDatasetH hdsDst; + VRTSourcedRasterBandH hbandDst; - len = strlen("SELECT AddRasterConstraints('','','',TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE,TRUE,FALSE);") + 1; - if (_schema != NULL) - len += strlen(_schema); - len += strlen(_table); - len += strlen(_column); + /* each tile is a VRT with constraints set for just the data required for the tile */ + for (ytile = 0; ytile < ntiles[1]; ytile++) { + for (xtile = 0; xtile < ntiles[0]; xtile++) { - sql = rtalloc(sizeof(char) * len); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for AddRasterConstraints statement\n")); - return 0; - } - sprintf(sql, "SELECT AddRasterConstraints('%s','%s','%s',TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,%s,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); + /* compute tile's upper-left corner */ + GDALApplyGeoTransform( + info->gt, + xtile * info->tile_size[0], ytile * info->tile_size[1], + &(gt[0]), &(gt[3]) + ); - append_stringbuffer(buffer, sql); - rtdealloc(sql); + /* create VRT dataset */ + hdsDst = VRTCreate(info->tile_size[0], info->tile_size[1]); + GDALSetProjection(hdsDst, info->srs); + GDALSetGeoTransform(hdsDst, gt); - return 1; -} + /* 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); -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; + if (info->hasnodata[i]) + GDALSetRasterNoDataValue(hbandDst, info->nodataval[i]); - char *_ovschema = NULL; - char *_ovtable = NULL; - char *_ovcolumn = NULL; + VRTAddSimpleSource( + hbandDst, GDALGetRasterBand(hdsSrc, info->nband[i]), + xtile * info->tile_size[0], ytile * info->tile_size[1], + info->tile_size[0], info->tile_size[1], + 0, 0, + info->tile_size[0], info->tile_size[1], + "near", VRT_NODATA_UNSET + ); + } - char *_schema = NULL; - char *_table = NULL; - char *_column = NULL; + /* make sure VRT reflects all changes */ + VRTFlushCache(hdsDst); - assert(ovtable != NULL); - assert(ovcolumn != NULL); - assert(table != NULL); - assert(column != NULL); - assert(factor >= MINOVFACTOR && factor <= MAXOVFACTOR); + /* convert VRT dataset to rt_raster */ + rast = rt_raster_from_gdal_dataset(hdsDst); - if (ovschema != NULL) { - char *tmp = chartrim(ovschema, "."); - _ovschema = chartrim(tmp, "\""); - rtdealloc(tmp); - } - _ovtable = chartrim(ovtable, "\""); - _ovcolumn = chartrim(ovcolumn, "\""); + /* set srid if provided */ + rt_raster_set_srid(rast, config->srid); - if (schema != NULL) { - char *tmp = chartrim(schema, "."); - _schema = chartrim(tmp, "\""); - rtdealloc(tmp); - } - _table = chartrim(table, "\""); - _column = chartrim(column, "\""); + /* convert rt_raster to hexwkb */ + hex = rt_raster_to_hexwkb(rast, &hexlen); + raster_destroy(rast); - 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); + /* add hexwkb to tileset */ + append_stringbuffer(tileset, hex); - sql = rtalloc(sizeof(char) * len); - if (sql == NULL) { - fprintf(stderr, _("Could not allocate memory for AddOverviewConstraints statement\n")); - 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); + rtdealloc(hex); + GDALClose(hdsDst); - if (_schema != NULL) - rtdealloc(_schema); - rtdealloc(_table); - rtdealloc(_column); + /* 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->copy_statements, + tileset, buffer + )) { + fprintf(stderr, _("Cannot convert raster tiles into INSERT or COPY statements\n")); + GDALClose(hdsSrc); + return 0; + } - append_stringbuffer(buffer, sql); - rtdealloc(sql); + rtdealloc_stringbuffer(tileset, 0); + } + } + } + + GDALClose(hdsSrc); + } return 1; } @@ -1412,7 +1477,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { assert(config->raster_column != NULL); if (config->transaction) { - if (!append_stringbuffer(buffer, "BEGIN;")) { + if (!append_sql_to_buffer(buffer, "BEGIN;")) { fprintf(stderr, _("Cannot add BEGIN statement to string buffer\n")); return 0; } @@ -1477,8 +1542,19 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { init_rastinfo(&rastinfo); init_stringbuffer(&tileset); + if (config->copy_statements && !copy_from( + config->schema, config->table, config->raster_column, + (config->file_column ? config->rt_filename[i] : NULL), + buffer + )) { + fprintf(stderr, _("Cannot add COPY statement to string buffer\n")); + rtdealloc_rastinfo(&rastinfo); + rtdealloc_stringbuffer(&tileset, 0); + return 0; + } + /* convert raster */ - if (!convert_raster(i, config, &rastinfo, &tileset)) { + if (!convert_raster(i, config, &rastinfo, &tileset, buffer)) { fprintf(stderr, _("Cannot process raster %s\n"), config->rt_file[i]); rtdealloc_rastinfo(&rastinfo); rtdealloc_stringbuffer(&tileset, 0); @@ -1486,7 +1562,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } /* process raster tiles into COPY or INSERT statements */ - if (!insert_records( + if (tileset.length && !insert_records( config->schema, config->table, config->raster_column, (config->file_column ? config->rt_filename[i] : NULL), config->copy_statements, &tileset, buffer @@ -1499,60 +1575,63 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { rtdealloc_stringbuffer(&tileset, 0); + if (config->copy_statements && !copy_from_end(buffer)) { + fprintf(stderr, _("Cannot add COPY end statement to string buffer\n")); + rtdealloc_rastinfo(&rastinfo); + return 0; + } + /* flush buffer after every raster */ flush_stringbuffer(buffer); /* overviews */ if (config->overview_count) { int j = 0; - STRINGBUFFER *ovset = NULL; - - /* build appropriate # of ovset */ - ovset = (STRINGBUFFER *) rtalloc(sizeof(struct stringbuffer_t) * config->overview_count); - if (ovset == NULL) { - fprintf(stderr, _("Cannot allocate memory for overview tiles\n")); - rtdealloc_rastinfo(&rastinfo); - return 0; - } - for (j = 0; j < config->overview_count; j++) - init_stringbuffer(&(ovset[j])); - if (!build_overviews(i, config, &rastinfo, ovset)) { - fprintf(stderr, _("Cannot create overviews for raster %s\n"), config->rt_file[i]); + for (j = 0; j < config->overview_count; j++) { - for (j = 0; j < config->overview_count; j++) - rtdealloc_stringbuffer(&(ovset[j]), 0); - rtdealloc(ovset); + if (config->copy_statements && !copy_from( + config->schema, config->overview_table[j], config->raster_column, + NULL, + buffer + )) { + fprintf(stderr, _("Cannot add COPY statement to string buffer\n")); + rtdealloc_rastinfo(&rastinfo); + rtdealloc_stringbuffer(&tileset, 0); + return 0; + } - rtdealloc_rastinfo(&rastinfo); - return 0; - } + if (!build_overview(i, config, &rastinfo, config->overview[j], &tileset, buffer)) { + fprintf(stderr, _("Cannot create overview of factor %d for raster %s\n"), config->overview[j], config->rt_file[i]); + rtdealloc_rastinfo(&rastinfo); + rtdealloc_stringbuffer(&tileset, 0); + return 0; + } - /* process overview tiles */ - for (j = 0; j < config->overview_count; j++) { - if (!insert_records( + if (tileset.length && !insert_records( config->schema, config->overview_table[j], config->raster_column, NULL, config->copy_statements, - &(ovset[j]), buffer + &tileset, buffer )) { fprintf(stderr, _("Cannot convert overview tiles into INSERT or COPY statements\n")); - - for (j = 0; j < config->overview_count; j++) - rtdealloc_stringbuffer(&(ovset[j]), 0); - rtdealloc(ovset); - rtdealloc_rastinfo(&rastinfo); + rtdealloc_stringbuffer(&tileset, 0); return 0; } + rtdealloc_stringbuffer(&tileset, 0); + /* flush buffer after every raster */ flush_stringbuffer(buffer); - } - /* free ovset */ - for (j = 0; j < config->overview_count; j++) - rtdealloc_stringbuffer(&(ovset[j]), 0); - rtdealloc(ovset); + if (config->copy_statements) { + if (!copy_from_end(buffer)) { + fprintf(stderr, _("Cannot add COPY end statement to string buffer\n")); + rtdealloc_rastinfo(&rastinfo); + return 0; + } + } + } } rtdealloc_rastinfo(&rastinfo); @@ -1644,7 +1723,7 @@ process_rasters(RTLOADERCFG *config, STRINGBUFFER *buffer) { } if (config->transaction) { - if (!append_stringbuffer(buffer, "END;")) { + if (!append_sql_to_buffer(buffer, "END;")) { fprintf(stderr, _("Cannot add END statement to string buffer\n")); return 0; }