LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitedriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 133 146 91.1 %
Date: 2024-11-25 13:07:18 Functions: 5 5 100.0 %

          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             : }

Generated by: LCOV version 1.14