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