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