]> granicus.if.org Git - postgis/commitdiff
Refactored for less memory usage by aggresively flushing string buffers.
authorBborie Park <bkpark at ucdavis.edu>
Wed, 14 Dec 2011 01:22:54 +0000 (01:22 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Wed, 14 Dec 2011 01:22:54 +0000 (01:22 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@8398 b70326c6-7e19-0410-871a-916f4a2858ee

raster/loader/raster2pgsql.c

index 6f8b74b7747e5aba3058cfb114189b959eb88802..c11f7f92512b641123427f31a68b87ef62b712d5 100644 (file)
@@ -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;
                }