Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Rasterlite driver
4 : * Purpose: Implement GDAL Rasterlite support using OGR SQLite driver
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : **********************************************************************
8 : * Copyright (c) 2009-2012, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_string.h"
30 : #include "ogr_api.h"
31 : #include "ogr_srs_api.h"
32 : #include "memdataset.h"
33 :
34 : #include "rasterlitedataset.h"
35 :
36 : /************************************************************************/
37 : /* RasterliteGetTileDriverOptions () */
38 : /************************************************************************/
39 :
40 62 : static char **RasterliteAddTileDriverOptionsForDriver(
41 : CSLConstList papszOptions, char **papszTileDriverOptions,
42 : const char *pszOptionName, const char *pszExpectedDriverName)
43 : {
44 62 : const char *pszVal = CSLFetchNameValue(papszOptions, pszOptionName);
45 62 : if (pszVal)
46 : {
47 : const char *pszDriverName =
48 0 : CSLFetchNameValueDef(papszOptions, "DRIVER", "GTiff");
49 0 : if (EQUAL(pszDriverName, pszExpectedDriverName))
50 : {
51 : papszTileDriverOptions =
52 0 : CSLSetNameValue(papszTileDriverOptions, pszOptionName, pszVal);
53 : }
54 : else
55 : {
56 0 : CPLError(CE_Warning, CPLE_NotSupported,
57 : "Unexpected option '%s' for driver '%s'", pszOptionName,
58 : pszDriverName);
59 : }
60 : }
61 62 : return papszTileDriverOptions;
62 : }
63 :
64 31 : char **RasterliteGetTileDriverOptions(CSLConstList papszOptions)
65 : {
66 : const char *pszDriverName =
67 31 : CSLFetchNameValueDef(papszOptions, "DRIVER", "GTiff");
68 :
69 31 : char **papszTileDriverOptions = nullptr;
70 :
71 31 : const char *pszQuality = CSLFetchNameValue(papszOptions, "QUALITY");
72 31 : if (pszQuality)
73 : {
74 0 : if (EQUAL(pszDriverName, "GTiff"))
75 : {
76 0 : papszTileDriverOptions = CSLSetNameValue(
77 : papszTileDriverOptions, "JPEG_QUALITY", pszQuality);
78 : }
79 0 : else if (EQUAL(pszDriverName, "JPEG") || EQUAL(pszDriverName, "WEBP"))
80 : {
81 0 : papszTileDriverOptions =
82 0 : CSLSetNameValue(papszTileDriverOptions, "QUALITY", pszQuality);
83 : }
84 : else
85 : {
86 0 : CPLError(CE_Warning, CPLE_NotSupported,
87 : "Unexpected option '%s' for driver '%s'", "QUALITY",
88 : pszDriverName);
89 : }
90 : }
91 :
92 31 : papszTileDriverOptions = RasterliteAddTileDriverOptionsForDriver(
93 : papszOptions, papszTileDriverOptions, "COMPRESS", "GTiff");
94 31 : papszTileDriverOptions = RasterliteAddTileDriverOptionsForDriver(
95 : papszOptions, papszTileDriverOptions, "PHOTOMETRIC", "GTiff");
96 :
97 31 : return papszTileDriverOptions;
98 : }
99 :
100 : /************************************************************************/
101 : /* RasterliteInsertSRID () */
102 : /************************************************************************/
103 :
104 28 : static int RasterliteInsertSRID(OGRDataSourceH hDS, const char *pszWKT)
105 : {
106 28 : int nAuthorityCode = 0;
107 56 : CPLString osAuthorityName, osProjCS, osProj4;
108 28 : if (pszWKT != nullptr && strlen(pszWKT) != 0)
109 : {
110 28 : OGRSpatialReferenceH hSRS = OSRNewSpatialReference(pszWKT);
111 28 : if (hSRS)
112 : {
113 28 : OSRSetAxisMappingStrategy(hSRS, OAMS_TRADITIONAL_GIS_ORDER);
114 :
115 28 : const char *pszAuthorityName = OSRGetAuthorityName(hSRS, nullptr);
116 28 : if (pszAuthorityName)
117 3 : osAuthorityName = pszAuthorityName;
118 :
119 28 : const char *pszProjCS = OSRGetAttrValue(hSRS, "PROJCS", 0);
120 28 : if (pszProjCS)
121 3 : osProjCS = pszProjCS;
122 :
123 28 : const char *pszAuthorityCode = OSRGetAuthorityCode(hSRS, nullptr);
124 28 : if (pszAuthorityCode)
125 3 : nAuthorityCode = atoi(pszAuthorityCode);
126 :
127 28 : char *pszProj4 = nullptr;
128 28 : if (OSRExportToProj4(hSRS, &pszProj4) != OGRERR_NONE)
129 : {
130 0 : CPLFree(pszProj4);
131 0 : pszProj4 = CPLStrdup("");
132 : }
133 28 : osProj4 = pszProj4;
134 28 : CPLFree(pszProj4);
135 : }
136 28 : OSRDestroySpatialReference(hSRS);
137 : }
138 :
139 28 : CPLString osSQL;
140 28 : int nSRSId = -1;
141 28 : if (nAuthorityCode != 0 && !osAuthorityName.empty())
142 : {
143 : osSQL.Printf("SELECT srid FROM spatial_ref_sys WHERE auth_srid = %d",
144 3 : nAuthorityCode);
145 : OGRLayerH hLyr =
146 3 : OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
147 3 : if (hLyr == nullptr)
148 : {
149 0 : nSRSId = nAuthorityCode;
150 :
151 0 : if (!osProjCS.empty())
152 : osSQL.Printf(
153 : "INSERT INTO spatial_ref_sys "
154 : "(srid, auth_name, auth_srid, ref_sys_name, proj4text) "
155 : "VALUES (%d, '%s', '%d', '%s', '%s')",
156 : nSRSId, osAuthorityName.c_str(), nAuthorityCode,
157 0 : osProjCS.c_str(), osProj4.c_str());
158 : else
159 : osSQL.Printf("INSERT INTO spatial_ref_sys "
160 : "(srid, auth_name, auth_srid, proj4text) "
161 : "VALUES (%d, '%s', '%d', '%s')",
162 : nSRSId, osAuthorityName.c_str(), nAuthorityCode,
163 0 : osProj4.c_str());
164 :
165 0 : OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
166 : }
167 : else
168 : {
169 3 : OGRFeatureH hFeat = OGR_L_GetNextFeature(hLyr);
170 3 : if (hFeat)
171 : {
172 3 : nSRSId = OGR_F_GetFieldAsInteger(hFeat, 0);
173 3 : OGR_F_Destroy(hFeat);
174 : }
175 3 : OGR_DS_ReleaseResultSet(hDS, hLyr);
176 : }
177 : }
178 :
179 56 : return nSRSId;
180 : }
181 :
182 : /************************************************************************/
183 : /* RasterliteCreateTables () */
184 : /************************************************************************/
185 :
186 28 : static OGRDataSourceH RasterliteCreateTables(OGRDataSourceH hDS,
187 : const char *pszTableName,
188 : int nSRSId, int bWipeExistingData)
189 : {
190 56 : CPLString osSQL;
191 :
192 56 : const CPLString osDBName = OGR_DS_GetName(hDS);
193 :
194 56 : CPLString osRasterLayer;
195 28 : osRasterLayer.Printf("%s_rasters", pszTableName);
196 :
197 56 : CPLString osMetadataLayer;
198 28 : osMetadataLayer.Printf("%s_metadata", pszTableName);
199 :
200 : OGRLayerH hLyr;
201 :
202 28 : if (OGR_DS_GetLayerByName(hDS, osRasterLayer.c_str()) == nullptr)
203 : {
204 : /* --------------------------------------------------------------------
205 : */
206 : /* The table don't exist. Create them */
207 : /* --------------------------------------------------------------------
208 : */
209 :
210 : /* Create _rasters table */
211 : osSQL.Printf("CREATE TABLE \"%s\" ("
212 : "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
213 : "raster BLOB NOT NULL)",
214 28 : osRasterLayer.c_str());
215 28 : OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
216 :
217 : /* Create _metadata table */
218 : osSQL.Printf("CREATE TABLE \"%s\" ("
219 : "id INTEGER NOT NULL PRIMARY KEY,"
220 : "source_name TEXT NOT NULL,"
221 : "tile_id INTEGER NOT NULL,"
222 : "width INTEGER NOT NULL,"
223 : "height INTEGER NOT NULL,"
224 : "pixel_x_size DOUBLE NOT NULL,"
225 : "pixel_y_size DOUBLE NOT NULL)",
226 28 : osMetadataLayer.c_str());
227 28 : OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
228 :
229 : /* Add geometry column to _metadata table */
230 : osSQL.Printf(
231 : "SELECT AddGeometryColumn('%s', 'geometry', %d, 'POLYGON', 2)",
232 28 : osMetadataLayer.c_str(), nSRSId);
233 28 : if ((hLyr = OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr)) ==
234 : nullptr)
235 : {
236 0 : CPLError(CE_Failure, CPLE_AppDefined,
237 : "Check that the OGR SQLite driver has Spatialite support");
238 0 : OGRReleaseDataSource(hDS);
239 0 : return nullptr;
240 : }
241 28 : OGR_DS_ReleaseResultSet(hDS, hLyr);
242 :
243 : /* Create spatial index on _metadata table */
244 : osSQL.Printf("SELECT CreateSpatialIndex('%s', 'geometry')",
245 28 : osMetadataLayer.c_str());
246 28 : if ((hLyr = OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr)) ==
247 : nullptr)
248 : {
249 0 : OGRReleaseDataSource(hDS);
250 0 : return nullptr;
251 : }
252 28 : OGR_DS_ReleaseResultSet(hDS, hLyr);
253 :
254 : /* Create statistics tables */
255 28 : osSQL.Printf("SELECT UpdateLayerStatistics()");
256 28 : CPLPushErrorHandler(CPLQuietErrorHandler);
257 28 : hLyr = OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
258 28 : CPLPopErrorHandler();
259 28 : OGR_DS_ReleaseResultSet(hDS, hLyr);
260 :
261 : /* Re-open the DB to take into account the new tables*/
262 28 : OGRReleaseDataSource(hDS);
263 :
264 28 : hDS = RasterliteOpenSQLiteDB(osDBName.c_str(), GA_Update);
265 : }
266 : else
267 : {
268 : /* Check that the existing SRS is consistent with the one of the new */
269 : /* data to be inserted */
270 : osSQL.Printf(
271 : "SELECT srid FROM geometry_columns WHERE f_table_name = '%s'",
272 0 : osMetadataLayer.c_str());
273 0 : hLyr = OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
274 0 : if (hLyr)
275 : {
276 0 : int nExistingSRID = -1;
277 0 : OGRFeatureH hFeat = OGR_L_GetNextFeature(hLyr);
278 0 : if (hFeat)
279 : {
280 0 : nExistingSRID = OGR_F_GetFieldAsInteger(hFeat, 0);
281 0 : OGR_F_Destroy(hFeat);
282 : }
283 0 : OGR_DS_ReleaseResultSet(hDS, hLyr);
284 :
285 0 : if (nExistingSRID != nSRSId)
286 : {
287 0 : if (bWipeExistingData)
288 : {
289 : osSQL.Printf("UPDATE geometry_columns SET srid = %d "
290 : "WHERE f_table_name = \"%s\"",
291 0 : nSRSId, osMetadataLayer.c_str());
292 0 : OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
293 :
294 : /* Re-open the DB to take into account the change of SRS */
295 0 : OGRReleaseDataSource(hDS);
296 :
297 0 : hDS = RasterliteOpenSQLiteDB(osDBName.c_str(), GA_Update);
298 : }
299 : else
300 : {
301 0 : CPLError(CE_Failure, CPLE_NotSupported,
302 : "New data has not the same SRS as existing data");
303 0 : OGRReleaseDataSource(hDS);
304 0 : return nullptr;
305 : }
306 : }
307 : }
308 :
309 0 : if (bWipeExistingData)
310 : {
311 0 : osSQL.Printf("DELETE FROM \"%s\"", osRasterLayer.c_str());
312 0 : OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
313 :
314 0 : osSQL.Printf("DELETE FROM \"%s\"", osMetadataLayer.c_str());
315 0 : OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
316 : }
317 : }
318 :
319 28 : return hDS;
320 : }
321 :
322 : /************************************************************************/
323 : /* RasterliteCreateCopy () */
324 : /************************************************************************/
325 :
326 32 : GDALDataset *RasterliteCreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
327 : CPL_UNUSED int bStrict, char **papszOptions,
328 : GDALProgressFunc pfnProgress,
329 : void *pProgressData)
330 : {
331 32 : const int nBands = poSrcDS->GetRasterCount();
332 32 : if (nBands == 0)
333 : {
334 1 : CPLError(CE_Failure, CPLE_NotSupported, "nBands == 0");
335 1 : return nullptr;
336 : }
337 :
338 : const char *pszDriverName =
339 31 : CSLFetchNameValueDef(papszOptions, "DRIVER", "GTiff");
340 31 : if (EQUAL(pszDriverName, "MEM") || EQUAL(pszDriverName, "VRT"))
341 : {
342 0 : CPLError(CE_Failure, CPLE_AppDefined,
343 : "GDAL %s driver cannot be used as underlying driver",
344 : pszDriverName);
345 0 : return nullptr;
346 : }
347 :
348 31 : GDALDriverH hTileDriver = GDALGetDriverByName(pszDriverName);
349 31 : if (hTileDriver == nullptr)
350 : {
351 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot load GDAL %s driver",
352 : pszDriverName);
353 0 : return nullptr;
354 : }
355 :
356 31 : GDALDriverH hMemDriver = GDALGetDriverByName("MEM");
357 31 : if (hMemDriver == nullptr)
358 : {
359 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot load GDAL MEM driver");
360 0 : return nullptr;
361 : }
362 :
363 31 : const int nXSize = GDALGetRasterXSize(poSrcDS);
364 31 : const int nYSize = GDALGetRasterYSize(poSrcDS);
365 :
366 : double adfGeoTransform[6];
367 31 : if (poSrcDS->GetGeoTransform(adfGeoTransform) != CE_None)
368 : {
369 0 : adfGeoTransform[0] = 0;
370 0 : adfGeoTransform[1] = 1;
371 0 : adfGeoTransform[2] = 0;
372 0 : adfGeoTransform[3] = 0;
373 0 : adfGeoTransform[4] = 0;
374 0 : adfGeoTransform[5] = -1;
375 : }
376 31 : else if (adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0)
377 : {
378 0 : CPLError(CE_Failure, CPLE_AppDefined,
379 : "Cannot use geotransform with rotational terms");
380 0 : return nullptr;
381 : }
382 :
383 : const bool bTiled =
384 31 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "TILED", "YES"));
385 : int nBlockXSize, nBlockYSize;
386 31 : if (bTiled)
387 : {
388 : nBlockXSize =
389 31 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "256"));
390 : nBlockYSize =
391 31 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "256"));
392 31 : if (nBlockXSize < 64)
393 0 : nBlockXSize = 64;
394 31 : else if (nBlockXSize > 4096)
395 0 : nBlockXSize = 4096;
396 31 : if (nBlockYSize < 64)
397 0 : nBlockYSize = 64;
398 31 : else if (nBlockYSize > 4096)
399 0 : nBlockYSize = 4096;
400 : }
401 : else
402 : {
403 0 : nBlockXSize = nXSize;
404 0 : nBlockYSize = nYSize;
405 : }
406 :
407 : /* -------------------------------------------------------------------- */
408 : /* Analyze arguments */
409 : /* -------------------------------------------------------------------- */
410 :
411 : /* Skip optional RASTERLITE: prefix */
412 31 : const char *pszFilenameWithoutPrefix = pszFilename;
413 31 : if (STARTS_WITH_CI(pszFilename, "RASTERLITE:"))
414 3 : pszFilenameWithoutPrefix += 11;
415 :
416 : char **papszTokens =
417 31 : CSLTokenizeStringComplex(pszFilenameWithoutPrefix, ",", FALSE, FALSE);
418 31 : const int nTokens = CSLCount(papszTokens);
419 62 : CPLString osDBName;
420 62 : CPLString osTableName;
421 31 : if (nTokens == 0)
422 : {
423 0 : osDBName = pszFilenameWithoutPrefix;
424 0 : osTableName = CPLGetBasename(pszFilenameWithoutPrefix);
425 : }
426 : else
427 : {
428 31 : osDBName = papszTokens[0];
429 :
430 : int i;
431 34 : for (i = 1; i < nTokens; i++)
432 : {
433 3 : if (STARTS_WITH_CI(papszTokens[i], "table="))
434 3 : osTableName = papszTokens[i] + 6;
435 : else
436 : {
437 0 : CPLError(CE_Warning, CPLE_AppDefined, "Invalid option : %s",
438 0 : papszTokens[i]);
439 : }
440 : }
441 : }
442 :
443 31 : CSLDestroy(papszTokens);
444 31 : papszTokens = nullptr;
445 :
446 : VSIStatBuf sBuf;
447 31 : const bool bExists = (VSIStat(osDBName.c_str(), &sBuf) == 0);
448 :
449 31 : if (osTableName.empty())
450 : {
451 28 : if (bExists)
452 : {
453 0 : CPLError(CE_Failure, CPLE_AppDefined,
454 : "Database already exists. Explicit table name must be "
455 : "specified");
456 0 : return nullptr;
457 : }
458 28 : osTableName = CPLGetBasename(osDBName.c_str());
459 : }
460 :
461 62 : CPLString osRasterLayer;
462 31 : osRasterLayer.Printf("%s_rasters", osTableName.c_str());
463 :
464 62 : CPLString osMetadataLayer;
465 31 : osMetadataLayer.Printf("%s_metadata", osTableName.c_str());
466 :
467 : /* -------------------------------------------------------------------- */
468 : /* Create or open the SQLite DB */
469 : /* -------------------------------------------------------------------- */
470 :
471 31 : OGRSFDriverH hSQLiteDriver = OGRGetDriverByName("SQLite");
472 31 : if (hSQLiteDriver == nullptr)
473 : {
474 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot load OGR SQLite driver");
475 0 : return nullptr;
476 : }
477 :
478 : OGRDataSourceH hDS;
479 :
480 31 : if (!bExists)
481 : {
482 31 : char **papszOGROptions = CSLAddString(nullptr, "SPATIALITE=YES");
483 31 : hDS = OGR_Dr_CreateDataSource(hSQLiteDriver, osDBName.c_str(),
484 : papszOGROptions);
485 31 : CSLDestroy(papszOGROptions);
486 : }
487 : else
488 : {
489 0 : hDS = RasterliteOpenSQLiteDB(osDBName.c_str(), GA_Update);
490 : }
491 :
492 31 : if (hDS == nullptr)
493 : {
494 3 : CPLError(CE_Failure, CPLE_AppDefined,
495 : "Cannot load or create SQLite database");
496 3 : return nullptr;
497 : }
498 :
499 56 : CPLString osSQL;
500 :
501 : /* -------------------------------------------------------------------- */
502 : /* Get the SRID for the SRS */
503 : /* -------------------------------------------------------------------- */
504 28 : int nSRSId = RasterliteInsertSRID(hDS, poSrcDS->GetProjectionRef());
505 :
506 : /* -------------------------------------------------------------------- */
507 : /* Create or wipe existing tables */
508 : /* -------------------------------------------------------------------- */
509 : const int bWipeExistingData =
510 28 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "WIPE", "NO"));
511 :
512 28 : hDS = RasterliteCreateTables(hDS, osTableName.c_str(), nSRSId,
513 : bWipeExistingData);
514 28 : if (hDS == nullptr)
515 1 : return nullptr;
516 :
517 27 : OGRLayerH hRasterLayer = OGR_DS_GetLayerByName(hDS, osRasterLayer.c_str());
518 : OGRLayerH hMetadataLayer =
519 27 : OGR_DS_GetLayerByName(hDS, osMetadataLayer.c_str());
520 27 : if (hRasterLayer == nullptr || hMetadataLayer == nullptr)
521 : {
522 0 : CPLError(CE_Failure, CPLE_AppDefined,
523 : "Cannot find metadata and/or raster tables");
524 0 : OGRReleaseDataSource(hDS);
525 0 : return nullptr;
526 : }
527 :
528 : /* -------------------------------------------------------------------- */
529 : /* Check if there is overlapping data and warn the user */
530 : /* -------------------------------------------------------------------- */
531 27 : double minx = adfGeoTransform[0];
532 27 : double maxx = adfGeoTransform[0] + nXSize * adfGeoTransform[1];
533 27 : double maxy = adfGeoTransform[3];
534 27 : double miny = adfGeoTransform[3] + nYSize * adfGeoTransform[5];
535 :
536 : osSQL.Printf(
537 : "SELECT COUNT(geometry) FROM \"%s\" "
538 : "WHERE rowid IN "
539 : "(SELECT pkid FROM \"idx_%s_metadata_geometry\" "
540 : "WHERE %s) AND %s",
541 : osMetadataLayer.c_str(), osTableName.c_str(),
542 54 : RasterliteGetSpatialFilterCond(minx, miny, maxx, maxy).c_str(),
543 54 : RasterliteGetPixelSizeCond(adfGeoTransform[1], -adfGeoTransform[5])
544 54 : .c_str());
545 :
546 27 : int nOverlappingGeoms = 0;
547 : OGRLayerH hCountLyr =
548 27 : OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr);
549 27 : if (hCountLyr)
550 : {
551 18 : OGRFeatureH hFeat = OGR_L_GetNextFeature(hCountLyr);
552 18 : if (hFeat)
553 : {
554 18 : nOverlappingGeoms = OGR_F_GetFieldAsInteger(hFeat, 0);
555 18 : OGR_F_Destroy(hFeat);
556 : }
557 18 : OGR_DS_ReleaseResultSet(hDS, hCountLyr);
558 : }
559 :
560 27 : if (nOverlappingGeoms != 0)
561 : {
562 0 : CPLError(CE_Warning, CPLE_AppDefined,
563 : "Raster tiles already exist in the %s table within "
564 : "the extent of the data to be inserted in",
565 : osTableName.c_str());
566 : }
567 :
568 : /* -------------------------------------------------------------------- */
569 : /* Iterate over blocks to add data into raster and metadata tables */
570 : /* -------------------------------------------------------------------- */
571 27 : int nXBlocks = (nXSize + nBlockXSize - 1) / nBlockXSize;
572 27 : int nYBlocks = (nYSize + nBlockYSize - 1) / nBlockYSize;
573 :
574 27 : GDALDataType eDataType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
575 27 : int nDataTypeSize = GDALGetDataTypeSize(eDataType) / 8;
576 27 : GByte *pabyMEMDSBuffer = reinterpret_cast<GByte *>(VSIMalloc3(
577 27 : nBlockXSize, nBlockYSize, cpl::fits_on<int>(nBands * nDataTypeSize)));
578 27 : if (pabyMEMDSBuffer == nullptr)
579 : {
580 0 : OGRReleaseDataSource(hDS);
581 0 : return nullptr;
582 : }
583 :
584 54 : CPLString osTempFileName;
585 27 : osTempFileName.Printf("/vsimem/%p", hDS);
586 :
587 27 : int nTileId = 0;
588 27 : int nBlocks = 0;
589 27 : int nTotalBlocks = nXBlocks * nYBlocks;
590 :
591 : char **papszTileDriverOptions =
592 27 : RasterliteGetTileDriverOptions(papszOptions);
593 :
594 27 : OGR_DS_ExecuteSQL(hDS, "BEGIN", nullptr, nullptr);
595 :
596 27 : CPLErr eErr = CE_None;
597 54 : for (int nBlockYOff = 0; eErr == CE_None && nBlockYOff < nYBlocks;
598 : nBlockYOff++)
599 : {
600 54 : for (int nBlockXOff = 0; eErr == CE_None && nBlockXOff < nXBlocks;
601 : nBlockXOff++)
602 : {
603 : /* --------------------------------------------------------------------
604 : */
605 : /* Create in-memory tile */
606 : /* --------------------------------------------------------------------
607 : */
608 27 : int nReqXSize = nBlockXSize;
609 27 : int nReqYSize = nBlockYSize;
610 27 : if ((nBlockXOff + 1) * nBlockXSize > nXSize)
611 27 : nReqXSize = nXSize - nBlockXOff * nBlockXSize;
612 27 : if ((nBlockYOff + 1) * nBlockYSize > nYSize)
613 27 : nReqYSize = nYSize - nBlockYOff * nBlockYSize;
614 :
615 27 : eErr = poSrcDS->RasterIO(
616 : GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
617 : nReqXSize, nReqYSize, pabyMEMDSBuffer, nReqXSize, nReqYSize,
618 : eDataType, nBands, nullptr, 0, 0, 0, nullptr);
619 27 : if (eErr != CE_None)
620 : {
621 0 : break;
622 : }
623 :
624 : auto poMEMDS = std::unique_ptr<MEMDataset>(MEMDataset::Create(
625 27 : "", nReqXSize, nReqYSize, 0, eDataType, nullptr));
626 64 : for (int iBand = 0; iBand < nBands; iBand++)
627 : {
628 37 : auto hBand = MEMCreateRasterBandEx(
629 37 : poMEMDS.get(), iBand + 1,
630 : pabyMEMDSBuffer +
631 37 : iBand * nDataTypeSize * nReqXSize * nReqYSize,
632 : eDataType, 0, 0, false);
633 37 : poMEMDS->AddMEMBand(hBand);
634 : }
635 :
636 27 : GDALDatasetH hOutDS = GDALCreateCopy(
637 27 : hTileDriver, osTempFileName.c_str(), poMEMDS.get(), FALSE,
638 : papszTileDriverOptions, nullptr, nullptr);
639 :
640 27 : if (!hOutDS)
641 : {
642 0 : eErr = CE_Failure;
643 0 : break;
644 : }
645 27 : GDALClose(hOutDS);
646 :
647 : /* --------------------------------------------------------------------
648 : */
649 : /* Insert new entry into raster table */
650 : /* --------------------------------------------------------------------
651 : */
652 27 : vsi_l_offset nDataLength = 0;
653 27 : GByte *pabyData = VSIGetMemFileBuffer(osTempFileName.c_str(),
654 : &nDataLength, FALSE);
655 :
656 27 : OGRFeatureH hFeat = OGR_F_Create(OGR_L_GetLayerDefn(hRasterLayer));
657 27 : OGR_F_SetFieldBinary(hFeat, 0, static_cast<int>(nDataLength),
658 : pabyData);
659 :
660 27 : if (OGR_L_CreateFeature(hRasterLayer, hFeat) != OGRERR_NONE)
661 0 : eErr = CE_Failure;
662 : /* Query raster ID to set it as the ID of the associated metadata */
663 27 : int nRasterID = static_cast<int>(OGR_F_GetFID(hFeat));
664 :
665 27 : OGR_F_Destroy(hFeat);
666 :
667 27 : VSIUnlink(osTempFileName.c_str());
668 27 : if (eErr == CE_Failure)
669 0 : break;
670 :
671 : /* --------------------------------------------------------------------
672 : */
673 : /* Insert new entry into metadata table */
674 : /* --------------------------------------------------------------------
675 : */
676 :
677 27 : hFeat = OGR_F_Create(OGR_L_GetLayerDefn(hMetadataLayer));
678 27 : OGR_F_SetFID(hFeat, nRasterID);
679 27 : OGR_F_SetFieldString(hFeat, 0, GDALGetDescription(poSrcDS));
680 27 : OGR_F_SetFieldInteger(hFeat, 1, nTileId++);
681 27 : OGR_F_SetFieldInteger(hFeat, 2, nReqXSize);
682 27 : OGR_F_SetFieldInteger(hFeat, 3, nReqYSize);
683 27 : OGR_F_SetFieldDouble(hFeat, 4, adfGeoTransform[1]);
684 27 : OGR_F_SetFieldDouble(hFeat, 5, -adfGeoTransform[5]);
685 :
686 27 : minx = adfGeoTransform[0] +
687 27 : (nBlockXSize * nBlockXOff) * adfGeoTransform[1];
688 27 : maxx = adfGeoTransform[0] +
689 27 : (nBlockXSize * nBlockXOff + nReqXSize) * adfGeoTransform[1];
690 27 : maxy = adfGeoTransform[3] +
691 27 : (nBlockYSize * nBlockYOff) * adfGeoTransform[5];
692 27 : miny = adfGeoTransform[3] +
693 27 : (nBlockYSize * nBlockYOff + nReqYSize) * adfGeoTransform[5];
694 :
695 27 : OGRGeometryH hRectangle = OGR_G_CreateGeometry(wkbPolygon);
696 27 : OGRGeometryH hLinearRing = OGR_G_CreateGeometry(wkbLinearRing);
697 27 : OGR_G_AddPoint_2D(hLinearRing, minx, miny);
698 27 : OGR_G_AddPoint_2D(hLinearRing, minx, maxy);
699 27 : OGR_G_AddPoint_2D(hLinearRing, maxx, maxy);
700 27 : OGR_G_AddPoint_2D(hLinearRing, maxx, miny);
701 27 : OGR_G_AddPoint_2D(hLinearRing, minx, miny);
702 27 : OGR_G_AddGeometryDirectly(hRectangle, hLinearRing);
703 :
704 27 : OGR_F_SetGeometryDirectly(hFeat, hRectangle);
705 :
706 27 : if (OGR_L_CreateFeature(hMetadataLayer, hFeat) != OGRERR_NONE)
707 0 : eErr = CE_Failure;
708 27 : OGR_F_Destroy(hFeat);
709 :
710 27 : nBlocks++;
711 27 : if (pfnProgress && !pfnProgress(1.0 * nBlocks / nTotalBlocks,
712 : nullptr, pProgressData))
713 0 : eErr = CE_Failure;
714 : }
715 : }
716 :
717 27 : VSIUnlink(osTempFileName);
718 27 : VSIUnlink((osTempFileName + ".aux.xml").c_str());
719 :
720 27 : if (eErr == CE_None)
721 27 : OGR_DS_ExecuteSQL(hDS, "COMMIT", nullptr, nullptr);
722 : else
723 0 : OGR_DS_ExecuteSQL(hDS, "ROLLBACK", nullptr, nullptr);
724 :
725 27 : CSLDestroy(papszTileDriverOptions);
726 :
727 27 : VSIFree(pabyMEMDSBuffer);
728 :
729 27 : OGRReleaseDataSource(hDS);
730 :
731 27 : if (eErr == CE_Failure)
732 0 : return nullptr;
733 :
734 27 : return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update));
735 : }
736 :
737 : /************************************************************************/
738 : /* RasterliteDelete () */
739 : /************************************************************************/
740 :
741 3 : CPLErr RasterliteDelete(CPL_UNUSED const char *pszFilename)
742 : {
743 3 : return CE_None;
744 : }
|