Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Implements OGRSQLiteDriver class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : *
9 : * Contributor: Alessandro Furieri, a.furieri@lqt.it
10 : * Portions of this module properly supporting SpatiaLite DB creation
11 : * Developed for Faunalia ( http://www.faunalia.it) with funding from
12 : * Regione Toscana - Settore SISTEMA INFORMATIVO TERRITORIALE ED AMBIENTALE
13 : *
14 : ******************************************************************************
15 : * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
16 : * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
17 : *
18 : * SPDX-License-Identifier: MIT
19 : ****************************************************************************/
20 :
21 : #include "cpl_port.h"
22 : #include "ogr_sqlite.h"
23 :
24 : #include <cstring>
25 : #include <string>
26 :
27 : #include "cpl_conv.h"
28 : #include "cpl_error.h"
29 : #include "cpl_string.h"
30 : #include "cpl_vsi.h"
31 : #include "gdal.h"
32 : #include "gdal_priv.h"
33 : #include "ogr_core.h"
34 : #include "sqlite3.h"
35 :
36 : /************************************************************************/
37 : /* OGRSQLiteDriverIdentify() */
38 : /************************************************************************/
39 :
40 47170 : static int OGRSQLiteDriverIdentify(GDALOpenInfo *poOpenInfo)
41 :
42 : {
43 47170 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "SQLITE:"))
44 : {
45 152 : return TRUE;
46 : }
47 :
48 94036 : CPLString osExt(CPLGetExtension(poOpenInfo->pszFilename));
49 47018 : if (EQUAL(osExt, "gpkg") && GDALGetDriverByName("GPKG") != nullptr)
50 : {
51 1420 : return FALSE;
52 : }
53 45598 : if (EQUAL(osExt, "mbtiles") && GDALGetDriverByName("MBTILES") != nullptr)
54 : {
55 261 : if (CSLCount(poOpenInfo->papszAllowedDrivers) == 1 &&
56 74 : EQUAL(poOpenInfo->papszAllowedDrivers[0], "SQLite"))
57 : {
58 74 : return TRUE;
59 : }
60 113 : return FALSE;
61 : }
62 :
63 45413 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "VirtualShape:") &&
64 2 : EQUAL(osExt, "shp"))
65 : {
66 2 : return TRUE;
67 : }
68 :
69 : #ifdef HAVE_RASTERLITE2
70 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "RASTERLITE2:"))
71 : return poOpenInfo->nOpenFlags & GDAL_OF_RASTER;
72 : #endif
73 :
74 45409 : if (EQUAL(poOpenInfo->pszFilename, ":memory:"))
75 92 : return TRUE;
76 :
77 : #ifdef SQLITE_OPEN_URI
78 : // This code enables support for named memory databases in SQLite.
79 : // Named memory databases use file name format
80 : // file:name?mode=memory&cache=shared
81 : // SQLITE_USE_URI is checked only to enable backward compatibility, in case
82 : // we accidentally hijacked some other format.
83 45319 : if (STARTS_WITH(poOpenInfo->pszFilename, "file:") &&
84 2 : CPLTestBool(CPLGetConfigOption("SQLITE_USE_URI", "YES")))
85 : {
86 2 : char *queryparams = strchr(poOpenInfo->pszFilename, '?');
87 2 : if (queryparams)
88 : {
89 2 : if (strstr(queryparams, "mode=memory") != nullptr)
90 2 : return TRUE;
91 : }
92 : }
93 : #endif
94 :
95 : /* -------------------------------------------------------------------- */
96 : /* Verify that the target is a real file, and has an */
97 : /* appropriate magic string at the beginning. */
98 : /* -------------------------------------------------------------------- */
99 45315 : if (poOpenInfo->nHeaderBytes < 100)
100 42187 : return FALSE;
101 :
102 : #ifdef ENABLE_SQL_SQLITE_FORMAT
103 3128 : if (STARTS_WITH(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
104 : "-- SQL SQLITE"))
105 : {
106 2 : return TRUE;
107 : }
108 3126 : if (STARTS_WITH(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
109 : "-- SQL RASTERLITE"))
110 : {
111 2 : return -1;
112 : }
113 3124 : if (STARTS_WITH(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
114 : "-- SQL MBTILES"))
115 : {
116 0 : if (GDALGetDriverByName("MBTILES") != nullptr)
117 0 : return FALSE;
118 0 : if (poOpenInfo->eAccess == GA_Update)
119 0 : return FALSE;
120 0 : return -1;
121 : }
122 : #endif
123 :
124 3124 : if (!STARTS_WITH(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
125 : "SQLite format 3"))
126 2591 : return FALSE;
127 :
128 : // In case we are opening /vsizip/foo.zip with a .gpkg inside
129 1599 : if ((memcmp(poOpenInfo->pabyHeader + 68, "GP10", 4) == 0 ||
130 533 : memcmp(poOpenInfo->pabyHeader + 68, "GP11", 4) == 0 ||
131 1075 : memcmp(poOpenInfo->pabyHeader + 68, "GPKG", 4) == 0) &&
132 9 : GDALGetDriverByName("GPKG") != nullptr)
133 : {
134 9 : return FALSE;
135 : }
136 :
137 : // Could be a Rasterlite or MBTiles file as well
138 524 : return -1;
139 : }
140 :
141 : /************************************************************************/
142 : /* Open() */
143 : /************************************************************************/
144 :
145 414 : static GDALDataset *OGRSQLiteDriverOpen(GDALOpenInfo *poOpenInfo)
146 :
147 : {
148 414 : if (OGRSQLiteDriverIdentify(poOpenInfo) == FALSE)
149 0 : return nullptr;
150 :
151 : /* -------------------------------------------------------------------- */
152 : /* Check VirtualShape:xxx.shp syntax */
153 : /* -------------------------------------------------------------------- */
154 414 : const auto nLen = strlen(poOpenInfo->pszFilename);
155 414 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "VirtualShape:") && nLen > 4 &&
156 1 : EQUAL(poOpenInfo->pszFilename + nLen - 4, ".SHP"))
157 : {
158 2 : auto poDS = std::make_unique<OGRSQLiteDataSource>();
159 :
160 1 : char **papszOptions = CSLAddString(nullptr, "SPATIALITE=YES");
161 1 : int nRet = poDS->Create(":memory:", papszOptions);
162 1 : poDS->SetDescription(poOpenInfo->pszFilename);
163 1 : CSLDestroy(papszOptions);
164 1 : if (!nRet)
165 : {
166 0 : return nullptr;
167 : }
168 :
169 : char *pszSQLiteFilename =
170 1 : CPLStrdup(poOpenInfo->pszFilename + strlen("VirtualShape:"));
171 2 : if (!std::unique_ptr<GDALDataset>(GDALDataset::Open(
172 1 : pszSQLiteFilename, GDAL_OF_VECTOR, nullptr, nullptr, nullptr)))
173 : {
174 0 : CPLFree(pszSQLiteFilename);
175 0 : return nullptr;
176 : }
177 :
178 1 : char *pszLastDot = strrchr(pszSQLiteFilename, '.');
179 1 : if (pszLastDot)
180 1 : *pszLastDot = '\0';
181 :
182 1 : const char *pszTableName = CPLGetBasename(pszSQLiteFilename);
183 :
184 1 : char *pszSQL = CPLStrdup(CPLSPrintf(
185 : "CREATE VIRTUAL TABLE %s USING VirtualShape(%s, CP1252, -1)",
186 : pszTableName, pszSQLiteFilename));
187 1 : poDS->ExecuteSQL(pszSQL, nullptr, nullptr);
188 1 : CPLFree(pszSQL);
189 1 : CPLFree(pszSQLiteFilename);
190 1 : poDS->DisableUpdate();
191 1 : return poDS.release();
192 : }
193 :
194 : /* -------------------------------------------------------------------- */
195 : /* We think this is really an SQLite database, go ahead and try */
196 : /* and open it. */
197 : /* -------------------------------------------------------------------- */
198 413 : OGRSQLiteDataSource *poDS = new OGRSQLiteDataSource();
199 :
200 413 : if (!poDS->Open(poOpenInfo))
201 : {
202 1 : delete poDS;
203 1 : return nullptr;
204 : }
205 : else
206 412 : return poDS;
207 : }
208 :
209 : /************************************************************************/
210 : /* Create() */
211 : /************************************************************************/
212 :
213 226 : static GDALDataset *OGRSQLiteDriverCreate(const char *pszName, int nBands,
214 : CPL_UNUSED int nXSize,
215 : CPL_UNUSED int nYSize,
216 : CPL_UNUSED GDALDataType eDT,
217 : char **papszOptions)
218 : {
219 226 : if (nBands != 0)
220 : {
221 0 : CPLError(CE_Failure, CPLE_NotSupported,
222 : "Raster creation through Create() interface is not supported. "
223 : "Only CreateCopy() is supported");
224 0 : return nullptr;
225 : }
226 :
227 : /* -------------------------------------------------------------------- */
228 : /* First, ensure there isn't any such file yet. */
229 : /* -------------------------------------------------------------------- */
230 : VSIStatBufL sStatBuf;
231 :
232 226 : if (VSIStatL(pszName, &sStatBuf) == 0)
233 : {
234 0 : CPLError(CE_Failure, CPLE_AppDefined,
235 : "It seems a file system object called '%s' already exists.",
236 : pszName);
237 :
238 0 : return nullptr;
239 : }
240 :
241 : /* -------------------------------------------------------------------- */
242 : /* Try to create datasource. */
243 : /* -------------------------------------------------------------------- */
244 226 : OGRSQLiteDataSource *poDS = new OGRSQLiteDataSource();
245 :
246 226 : if (!poDS->Create(pszName, papszOptions))
247 : {
248 5 : delete poDS;
249 5 : return nullptr;
250 : }
251 :
252 221 : return poDS;
253 : }
254 :
255 : /************************************************************************/
256 : /* Delete() */
257 : /************************************************************************/
258 :
259 86 : static CPLErr OGRSQLiteDriverDelete(const char *pszName)
260 : {
261 86 : if (VSIUnlink(pszName) == 0)
262 64 : return CE_None;
263 : else
264 22 : return CE_Failure;
265 : }
266 :
267 : /************************************************************************/
268 : /* RegisterOGRSQLite() */
269 : /************************************************************************/
270 :
271 1595 : void RegisterOGRSQLite()
272 :
273 : {
274 1595 : if (!GDAL_CHECK_VERSION("SQLite driver"))
275 302 : return;
276 :
277 1595 : if (GDALGetDriverByName("SQLite") != nullptr)
278 302 : return;
279 :
280 1293 : GDALDriver *poDriver = new GDALDriver();
281 :
282 1293 : poDriver->SetDescription("SQLite");
283 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
284 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
285 1293 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_LAYER, "YES");
286 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
287 1293 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
288 1293 : poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
289 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES");
290 1293 : poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES");
291 1293 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
292 1293 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "SQLITE OGRSQL");
293 :
294 : #ifdef HAVE_RASTERLITE2
295 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
296 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
297 : "SQLite / Spatialite / RasterLite2");
298 : #else
299 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SQLite / Spatialite");
300 : #endif
301 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/sqlite.html");
302 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "sqlite db");
303 :
304 1293 : poDriver->SetMetadataItem(
305 : GDAL_DMD_OPENOPTIONLIST,
306 : "<OpenOptionList>"
307 : " <Option name='LIST_ALL_TABLES' type='boolean' description='Whether "
308 : "all tables, including non-spatial ones, should be listed' "
309 : "default='NO'/>"
310 : " <Option name='LIST_VIRTUAL_OGR' type='boolean' description='Whether "
311 : "VirtualOGR virtual tables should be listed. Should only be enabled on "
312 : "trusted datasources to avoid potential safety issues' default='NO'/>"
313 : " <Option name='PRELUDE_STATEMENTS' type='string' description='SQL "
314 : "statement(s) to send on the SQLite connection before any other ones'/>"
315 : #ifdef HAVE_RASTERLITE2
316 : " <Option name='1BIT_AS_8BIT' type='boolean' scope='raster' "
317 : "description='Whether to promote 1-bit monochrome raster as 8-bit, so "
318 : "as to have higher quality overviews' default='YES'/>"
319 : #endif
320 1293 : "</OpenOptionList>");
321 :
322 : CPLString osCreationOptions(
323 : "<CreationOptionList>"
324 : #ifdef HAVE_SPATIALITE
325 : " <Option name='SPATIALITE' type='boolean' description='Whether to "
326 : "create a Spatialite database' default='NO'/>"
327 : #endif
328 : " <Option name='METADATA' type='boolean' description='Whether to "
329 : "create the geometry_columns and spatial_ref_sys tables' "
330 : "default='YES'/>"
331 : " <Option name='INIT_WITH_EPSG' type='boolean' description='Whether "
332 : "to insert the content of the EPSG CSV files into the spatial_ref_sys "
333 : "table ' default='NO'/>"
334 : #ifdef HAVE_RASTERLITE2
335 : " <Option name='APPEND_SUBDATASET' scope='raster' type='boolean' "
336 : "description='Whether to add the raster to the existing file' "
337 : "default='NO'/>"
338 : " <Option name='COVERAGE' scope='raster' type='string' "
339 : "description='Coverage name'/>"
340 : " <Option name='SECTION' scope='raster' type='string' "
341 : "description='Section name'/>"
342 : " <Option name='COMPRESS' scope='raster' type='string-select' "
343 : "description='Raster compression' default='NONE'>"
344 : " <Value>NONE</Value>"
345 : #endif
346 2586 : );
347 : #ifdef HAVE_RASTERLITE2
348 : if (rl2_is_supported_codec(RL2_COMPRESSION_DEFLATE))
349 : osCreationOptions += " <Value>DEFLATE</Value>";
350 : if (rl2_is_supported_codec(RL2_COMPRESSION_LZMA))
351 : osCreationOptions += " <Value>LZMA</Value>";
352 : if (rl2_is_supported_codec(RL2_COMPRESSION_PNG))
353 : osCreationOptions += " <Value>PNG</Value>";
354 : if (rl2_is_supported_codec(RL2_COMPRESSION_CCITTFAX4))
355 : osCreationOptions += " <Value>CCITTFAX4</Value>";
356 : if (rl2_is_supported_codec(RL2_COMPRESSION_JPEG))
357 : osCreationOptions += " <Value>JPEG</Value>";
358 : if (rl2_is_supported_codec(RL2_COMPRESSION_LOSSY_WEBP))
359 : osCreationOptions += " <Value>WEBP</Value>";
360 : if (rl2_is_supported_codec(RL2_COMPRESSION_LOSSY_JP2))
361 : osCreationOptions += " <Value>JPEG2000</Value>";
362 : #endif
363 : osCreationOptions +=
364 : #ifdef HAVE_RASTERLITE2
365 : " </Option>"
366 : " <Option name='QUALITY' scope='raster' type='int' description='Image "
367 : "quality for JPEG, WEBP and JPEG2000 compressions'/>"
368 : " <Option name='PIXEL_TYPE' scope='raster' type='string-select' "
369 : "description='Raster pixel type. Determines photometric "
370 : "interpretation'>"
371 : " <Value>MONOCHROME</Value>"
372 : " <Value>PALETTE</Value>"
373 : " <Value>GRAYSCALE</Value>"
374 : " <Value>RGB</Value>"
375 : " <Value>MULTIBAND</Value>"
376 : " <Value>DATAGRID</Value>"
377 : " </Option>"
378 : " <Option name='BLOCKXSIZE' scope='raster' type='int' "
379 : "description='Block width' default='512'/>"
380 : " <Option name='BLOCKYSIZE' scope='raster' type='int' "
381 : "description='Block height' default='512'/>"
382 : " <Option name='NBITS' scope='raster' type='int' description='Force "
383 : "bit width. 1, 2 or 4 are supported'/>"
384 : " <Option name='PYRAMIDIZE' scope='raster' type='boolean' "
385 : "description='Whether to automatically build relevant "
386 : "pyramids/overviews' default='NO'/>"
387 : #endif
388 1293 : "</CreationOptionList>";
389 :
390 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST, osCreationOptions);
391 :
392 1293 : poDriver->SetMetadataItem(
393 : GDAL_DS_LAYER_CREATIONOPTIONLIST,
394 : "<LayerCreationOptionList>"
395 : " <Option name='FORMAT' type='string-select' description='Format of "
396 : "geometry columns'>"
397 : " <Value>WKB</Value>"
398 : " <Value>WKT</Value>"
399 : #ifdef HAVE_SPATIALITE
400 : " <Value>SPATIALITE</Value>"
401 : #endif
402 : " </Option>"
403 : " <Option name='GEOMETRY_NAME' type='string' description='Name of "
404 : "geometry column. Defaults to WKT_GEOMETRY for FORMAT=WKT or GEOMETRY "
405 : "otherwise'/>"
406 : " <Option name='LAUNDER' type='boolean' description='Whether layer "
407 : "and field names will be laundered' default='YES'/>"
408 : #ifdef HAVE_SPATIALITE
409 : " <Option name='SPATIAL_INDEX' type='boolean' description='Whether to "
410 : "create a spatial index for Spatialite databases' default='YES'/>"
411 : " <Option name='COMPRESS_GEOM' type='boolean' description='Whether to "
412 : "use compressed format of Spatialite geometries' default='NO'/>"
413 : #endif
414 : " <Option name='SRID' type='int' description='Forced SRID of the "
415 : "layer'/>"
416 : " <Option name='COMPRESS_COLUMNS' type='string' "
417 : "description='=column_name1[,column_name2, ...]. list of (String) "
418 : "columns that must be compressed with ZLib DEFLATE algorithm'/>"
419 : " <Option name='OVERWRITE' type='boolean' description='Whether to "
420 : "overwrite an existing table with the layer name to be created' "
421 : "default='NO'/>"
422 : " <Option name='FID' type='string' description='Name of the FID "
423 : "column to create' default='OGC_FID'/>"
424 : #if SQLITE_VERSION_NUMBER >= 3037000
425 : " <Option name='STRICT' type='boolean' description='Whether to create "
426 : "the table in STRICT mode (only compatible of readers with sqlite >= "
427 : "3.37)' default='NO'/>"
428 : #endif
429 1293 : "</LayerCreationOptionList>");
430 :
431 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES,
432 : "Integer Integer64 Real String Date DateTime "
433 : "Time Binary IntegerList Integer64List "
434 1293 : "RealList StringList");
435 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES,
436 1293 : "Boolean Int16 Float32");
437 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
438 1293 : "WidthPrecision Nullable Default Unique");
439 1293 : poDriver->SetMetadataItem(
440 : GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
441 1293 : "Name Type WidthPrecision Nullable Default Unique");
442 :
443 : #ifdef HAVE_RASTERLITE2
444 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
445 : "Byte Int8 UInt16 Int16 UInt32 Int32 Float32 "
446 : "Float64");
447 : #endif
448 1293 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_FIELDS, "YES");
449 1293 : poDriver->SetMetadataItem(GDAL_DCAP_DEFAULT_FIELDS, "YES");
450 1293 : poDriver->SetMetadataItem(GDAL_DCAP_UNIQUE_FIELDS, "YES");
451 1293 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES");
452 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
453 1293 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES");
454 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RELATIONSHIPS, "YES");
455 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_RELATIONSHIP, "YES");
456 1293 : poDriver->SetMetadataItem(GDAL_DMD_RELATIONSHIP_FLAGS,
457 1293 : "OneToMany Association Composite");
458 1293 : poDriver->SetMetadataItem(GDAL_DMD_RELATIONSHIP_RELATED_TABLE_TYPES,
459 1293 : "features");
460 :
461 : #ifdef ENABLE_SQL_SQLITE_FORMAT
462 1293 : poDriver->SetMetadataItem("ENABLE_SQL_SQLITE_FORMAT", "YES");
463 : #endif
464 : #ifdef SQLITE_HAS_COLUMN_METADATA
465 1293 : poDriver->SetMetadataItem("SQLITE_HAS_COLUMN_METADATA", "YES");
466 : #endif
467 :
468 1293 : poDriver->pfnOpen = OGRSQLiteDriverOpen;
469 1293 : poDriver->pfnIdentify = OGRSQLiteDriverIdentify;
470 1293 : poDriver->pfnCreate = OGRSQLiteDriverCreate;
471 : #ifdef HAVE_RASTERLITE2
472 : poDriver->pfnCreateCopy = OGRSQLiteDriverCreateCopy;
473 : #endif
474 1293 : poDriver->pfnDelete = OGRSQLiteDriverDelete;
475 1293 : poDriver->pfnUnloadDriver = OGRSQLiteDriverUnload;
476 :
477 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
478 : }
|