LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqliteexecutesql.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 459 511 89.8 %
Date: 2024-11-25 13:07:18 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Run SQL requests with SQLite SQL engine
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2012-2013, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_sqlite.h"
      14             : #include "ogrsqliteexecutesql.h"
      15             : #include "ogrsqlitevirtualogr.h"
      16             : #include "ogrsqliteutility.h"
      17             : 
      18             : #include <cctype>
      19             : #include <cstdio>
      20             : #include <cstring>
      21             : 
      22             : #include "cpl_conv.h"
      23             : #include "cpl_error.h"
      24             : #include "cpl_multiproc.h"
      25             : #include "cpl_port.h"
      26             : #include "cpl_string.h"
      27             : #include "cpl_vsi.h"
      28             : #include "gdal_priv.h"
      29             : #include "ogr_api.h"
      30             : #include "ogr_core.h"
      31             : #include "ogr_feature.h"
      32             : #include "ogr_geometry.h"
      33             : #include "ogr_spatialref.h"
      34             : #include "sqlite3.h"
      35             : 
      36             : /************************************************************************/
      37             : /*                       OGR2SQLITEExtractUnquotedString()              */
      38             : /************************************************************************/
      39             : 
      40         389 : static CPLString OGR2SQLITEExtractUnquotedString(const char **ppszSQLCommand)
      41             : {
      42         389 :     CPLString osRet;
      43         389 :     const char *pszSQLCommand = *ppszSQLCommand;
      44         389 :     if (*pszSQLCommand == '"' || *pszSQLCommand == '\'')
      45             :     {
      46          19 :         const char chQuoteChar = *pszSQLCommand;
      47          19 :         pszSQLCommand++;
      48             : 
      49         193 :         while (*pszSQLCommand != '\0')
      50             :         {
      51         193 :             if (*pszSQLCommand == chQuoteChar &&
      52          19 :                 pszSQLCommand[1] == chQuoteChar)
      53             :             {
      54           0 :                 pszSQLCommand++;
      55           0 :                 osRet += chQuoteChar;
      56             :             }
      57         193 :             else if (*pszSQLCommand == chQuoteChar)
      58             :             {
      59          19 :                 pszSQLCommand++;
      60          19 :                 break;
      61             :             }
      62             :             else
      63         174 :                 osRet += *pszSQLCommand;
      64             : 
      65         174 :             pszSQLCommand++;
      66          19 :         }
      67             :     }
      68             :     else
      69             :     {
      70         370 :         bool bNotATableName = false;
      71         370 :         char chQuoteChar = 0;
      72         370 :         int nParenthesisLevel = 0;
      73        2974 :         while (*pszSQLCommand != '\0')
      74             :         {
      75        2932 :             if (*pszSQLCommand == chQuoteChar &&
      76           0 :                 pszSQLCommand[1] == chQuoteChar)
      77             :             {
      78           0 :                 osRet += *pszSQLCommand;
      79           0 :                 pszSQLCommand++;
      80             :             }
      81        2932 :             else if (*pszSQLCommand == chQuoteChar)
      82             :             {
      83           0 :                 chQuoteChar = 0;
      84             :             }
      85        2932 :             else if (chQuoteChar == 0)
      86             :             {
      87        2932 :                 if (*pszSQLCommand == '(')
      88             :                 {
      89           2 :                     bNotATableName = true;
      90           2 :                     nParenthesisLevel++;
      91             :                 }
      92        2930 :                 else if (*pszSQLCommand == ')')
      93             :                 {
      94           6 :                     nParenthesisLevel--;
      95           6 :                     if (nParenthesisLevel < 0)
      96           4 :                         break;
      97             :                 }
      98        2924 :                 else if (*pszSQLCommand == '"' || *pszSQLCommand == '\'')
      99             :                 {
     100           0 :                     chQuoteChar = *pszSQLCommand;
     101             :                 }
     102        2924 :                 else if (nParenthesisLevel == 0 &&
     103        2908 :                          (isspace(static_cast<unsigned char>(*pszSQLCommand)) ||
     104        2588 :                           *pszSQLCommand == '.' || *pszSQLCommand == ','))
     105             :                 {
     106             :                     break;
     107             :                 }
     108             :             }
     109             : 
     110        2604 :             osRet += *pszSQLCommand;
     111        2604 :             pszSQLCommand++;
     112             :         }
     113         370 :         if (bNotATableName)
     114           2 :             osRet.clear();
     115             :     }
     116             : 
     117         389 :     *ppszSQLCommand = pszSQLCommand;
     118             : 
     119         389 :     return osRet;
     120             : }
     121             : 
     122             : /************************************************************************/
     123             : /*                      OGR2SQLITEExtractLayerDesc()                    */
     124             : /************************************************************************/
     125             : 
     126         374 : static LayerDesc OGR2SQLITEExtractLayerDesc(const char **ppszSQLCommand)
     127             : {
     128         748 :     std::string osStr;
     129         374 :     const char *pszSQLCommand = *ppszSQLCommand;
     130         374 :     LayerDesc oLayerDesc;
     131             : 
     132         374 :     while (isspace(static_cast<unsigned char>(*pszSQLCommand)))
     133           0 :         pszSQLCommand++;
     134             : 
     135         374 :     const char *pszOriginalStrStart = pszSQLCommand;
     136         374 :     oLayerDesc.osOriginalStr = pszSQLCommand;
     137             : 
     138         374 :     osStr = OGR2SQLITEExtractUnquotedString(&pszSQLCommand);
     139             : 
     140         374 :     if (*pszSQLCommand == '.')
     141             :     {
     142           7 :         oLayerDesc.osDSName = osStr;
     143           7 :         pszSQLCommand++;
     144             :         oLayerDesc.osLayerName =
     145           7 :             OGR2SQLITEExtractUnquotedString(&pszSQLCommand);
     146             :     }
     147             :     else
     148             :     {
     149         367 :         oLayerDesc.osLayerName = std::move(osStr);
     150             :     }
     151             : 
     152         374 :     oLayerDesc.osOriginalStr.resize(pszSQLCommand - pszOriginalStrStart);
     153             : 
     154         374 :     *ppszSQLCommand = pszSQLCommand;
     155             : 
     156         748 :     return oLayerDesc;
     157             : }
     158             : 
     159             : /************************************************************************/
     160             : /*                           OGR2SQLITEAddLayer()                       */
     161             : /************************************************************************/
     162             : 
     163         374 : static void OGR2SQLITEAddLayer(const char *&pszStart, int &nNum,
     164             :                                const char *&pszSQLCommand,
     165             :                                std::set<LayerDesc> &oSet,
     166             :                                CPLString &osModifiedSQL)
     167             : {
     168         748 :     CPLString osTruncated(pszStart);
     169         374 :     osTruncated.resize(pszSQLCommand - pszStart);
     170         374 :     osModifiedSQL += osTruncated;
     171         374 :     pszStart = pszSQLCommand;
     172         374 :     LayerDesc oLayerDesc = OGR2SQLITEExtractLayerDesc(&pszSQLCommand);
     173         374 :     bool bInsert = true;
     174         374 :     if (oLayerDesc.osDSName.empty())
     175             :     {
     176         367 :         osTruncated = pszStart;
     177         367 :         osTruncated.resize(pszSQLCommand - pszStart);
     178         367 :         osModifiedSQL += osTruncated;
     179             :     }
     180             :     else
     181             :     {
     182           7 :         std::set<LayerDesc>::iterator oIter = oSet.find(oLayerDesc);
     183           7 :         if (oIter == oSet.end())
     184             :         {
     185             :             oLayerDesc.osSubstitutedName =
     186           7 :                 CPLString().Printf("_OGR_%d", nNum++);
     187           7 :             osModifiedSQL += "\"";
     188           7 :             osModifiedSQL += oLayerDesc.osSubstitutedName;
     189           7 :             osModifiedSQL += "\"";
     190             :         }
     191             :         else
     192             :         {
     193           0 :             osModifiedSQL += (*oIter).osSubstitutedName;
     194           0 :             bInsert = false;
     195             :         }
     196             :     }
     197         374 :     if (bInsert)
     198             :     {
     199         374 :         oSet.insert(oLayerDesc);
     200             :     }
     201         374 :     pszStart = pszSQLCommand;
     202         374 : }
     203             : 
     204             : /************************************************************************/
     205             : /*                         StartsAsSQLITEKeyWord()                      */
     206             : /************************************************************************/
     207             : 
     208         294 : static int StartsAsSQLITEKeyWord(const char *pszStr)
     209             : {
     210          85 :     for (const char *pszKeyword : {"WHERE", "GROUP", "ORDER", "JOIN", "UNION",
     211         379 :                                    "INTERSECT", "EXCEPT", "LIMIT"})
     212             :     {
     213         372 :         if (STARTS_WITH_CI(pszStr, pszKeyword))
     214         287 :             return TRUE;
     215             :     }
     216           7 :     return FALSE;
     217             : }
     218             : 
     219             : /************************************************************************/
     220             : /*                     OGR2SQLITEGetPotentialLayerNames()               */
     221             : /************************************************************************/
     222             : 
     223         639 : static void OGR2SQLITEGetPotentialLayerNamesInternal(
     224             :     const char **ppszSQLCommand, std::set<LayerDesc> &oSetLayers,
     225             :     std::set<CPLString> &oSetSpatialIndex, CPLString &osModifiedSQL, int &nNum)
     226             : {
     227         639 :     const char *pszSQLCommand = *ppszSQLCommand;
     228         639 :     const char *pszStart = pszSQLCommand;
     229         639 :     char ch = '\0';
     230         639 :     int nParenthesisLevel = 0;
     231         639 :     bool bLookforFTableName = false;
     232             : 
     233       24729 :     while ((ch = *pszSQLCommand) != '\0')
     234             :     {
     235       24092 :         if (ch == '(')
     236         544 :             nParenthesisLevel++;
     237       23548 :         else if (ch == ')')
     238             :         {
     239         556 :             nParenthesisLevel--;
     240         556 :             if (nParenthesisLevel < 0)
     241             :             {
     242           2 :                 pszSQLCommand++;
     243           2 :                 break;
     244             :             }
     245             :         }
     246             : 
     247             :         /* Skip literals and strings */
     248       24090 :         if (ch == '\'' || ch == '"')
     249             :         {
     250         495 :             char chEscapeChar = ch;
     251         495 :             pszSQLCommand++;
     252       16948 :             while ((ch = *pszSQLCommand) != '\0')
     253             :             {
     254       16948 :                 if (ch == chEscapeChar && pszSQLCommand[1] == chEscapeChar)
     255           0 :                     pszSQLCommand++;
     256       16948 :                 else if (ch == chEscapeChar)
     257             :                 {
     258         495 :                     pszSQLCommand++;
     259         495 :                     break;
     260             :                 }
     261       16453 :                 pszSQLCommand++;
     262         495 :             }
     263             :         }
     264             : 
     265       23595 :         else if (STARTS_WITH_CI(pszSQLCommand, "ogr_layer_"))
     266             :         {
     267         182 :             while (*pszSQLCommand != '\0' && *pszSQLCommand != '(')
     268         172 :                 pszSQLCommand++;
     269             : 
     270          10 :             if (*pszSQLCommand != '(')
     271           0 :                 break;
     272             : 
     273          10 :             pszSQLCommand++;
     274          10 :             nParenthesisLevel++;
     275             : 
     276          10 :             while (isspace(static_cast<unsigned char>(*pszSQLCommand)))
     277           0 :                 pszSQLCommand++;
     278             : 
     279          10 :             OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers,
     280             :                                osModifiedSQL);
     281             :         }
     282             : 
     283       23585 :         else if (bLookforFTableName &&
     284           7 :                  STARTS_WITH_CI(pszSQLCommand, "f_table_name") &&
     285           1 :                  (pszSQLCommand[strlen("f_table_name")] == '=' ||
     286           1 :                   isspace(static_cast<unsigned char>(
     287           1 :                       pszSQLCommand[strlen("f_table_name")]))))
     288             :         {
     289           1 :             pszSQLCommand += strlen("f_table_name");
     290             : 
     291           2 :             while (isspace(static_cast<unsigned char>(*pszSQLCommand)))
     292           1 :                 pszSQLCommand++;
     293             : 
     294           1 :             if (*pszSQLCommand == '=')
     295             :             {
     296           1 :                 pszSQLCommand++;
     297             : 
     298           2 :                 while (isspace(static_cast<unsigned char>(*pszSQLCommand)))
     299           1 :                     pszSQLCommand++;
     300             : 
     301             :                 oSetSpatialIndex.insert(
     302           1 :                     OGR2SQLITEExtractUnquotedString(&pszSQLCommand));
     303             :             }
     304             : 
     305           1 :             bLookforFTableName = false;
     306             :         }
     307             : 
     308       23584 :         else if (STARTS_WITH_CI(pszSQLCommand, "FROM") &&
     309         467 :                  isspace(
     310         467 :                      static_cast<unsigned char>(pszSQLCommand[strlen("FROM")])))
     311             :         {
     312         338 :             pszSQLCommand += strlen("FROM") + 1;
     313             : 
     314         338 :             while (isspace(static_cast<unsigned char>(*pszSQLCommand)))
     315           0 :                 pszSQLCommand++;
     316             : 
     317         338 :             if (STARTS_WITH_CI(pszSQLCommand, "SpatialIndex") &&
     318           1 :                 isspace(static_cast<unsigned char>(
     319           1 :                     pszSQLCommand[strlen("SpatialIndex")])))
     320             :             {
     321           1 :                 pszSQLCommand += strlen("SpatialIndex") + 1;
     322             : 
     323           1 :                 bLookforFTableName = true;
     324             : 
     325           1 :                 continue;
     326             :             }
     327             : 
     328         337 :             if (*pszSQLCommand == '(')
     329             :             {
     330           2 :                 pszSQLCommand++;
     331             : 
     332           2 :                 CPLString osTruncated(pszStart);
     333           2 :                 osTruncated.resize(pszSQLCommand - pszStart);
     334           2 :                 osModifiedSQL += osTruncated;
     335             : 
     336           2 :                 OGR2SQLITEGetPotentialLayerNamesInternal(
     337             :                     &pszSQLCommand, oSetLayers, oSetSpatialIndex, osModifiedSQL,
     338             :                     nNum);
     339             : 
     340           2 :                 pszStart = pszSQLCommand;
     341             :             }
     342             :             else
     343         335 :                 OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers,
     344             :                                    osModifiedSQL);
     345             : 
     346         349 :             while (*pszSQLCommand != '\0')
     347             :             {
     348         303 :                 if (isspace(static_cast<unsigned char>(*pszSQLCommand)))
     349             :                 {
     350         295 :                     pszSQLCommand++;
     351         295 :                     while (isspace(static_cast<unsigned char>(*pszSQLCommand)))
     352           0 :                         pszSQLCommand++;
     353             : 
     354         295 :                     if (STARTS_WITH_CI(pszSQLCommand, "AS"))
     355             :                     {
     356           0 :                         pszSQLCommand += 2;
     357           0 :                         while (
     358           0 :                             isspace(static_cast<unsigned char>(*pszSQLCommand)))
     359           0 :                             pszSQLCommand++;
     360             :                     }
     361             : 
     362             :                     /* Skip alias */
     363         295 :                     if (*pszSQLCommand != '\0' && *pszSQLCommand != ',')
     364             :                     {
     365         294 :                         if (StartsAsSQLITEKeyWord(pszSQLCommand))
     366         287 :                             break;
     367           7 :                         OGR2SQLITEExtractUnquotedString(&pszSQLCommand);
     368             :                     }
     369             :                 }
     370           8 :                 else if (*pszSQLCommand == ',')
     371             :                 {
     372           4 :                     pszSQLCommand++;
     373           8 :                     while (isspace(static_cast<unsigned char>(*pszSQLCommand)))
     374           4 :                         pszSQLCommand++;
     375             : 
     376           4 :                     if (*pszSQLCommand == '(')
     377             :                     {
     378           0 :                         pszSQLCommand++;
     379             : 
     380           0 :                         CPLString osTruncated(pszStart);
     381           0 :                         osTruncated.resize(pszSQLCommand - pszStart);
     382           0 :                         osModifiedSQL += osTruncated;
     383             : 
     384           0 :                         OGR2SQLITEGetPotentialLayerNamesInternal(
     385             :                             &pszSQLCommand, oSetLayers, oSetSpatialIndex,
     386             :                             osModifiedSQL, nNum);
     387             : 
     388           0 :                         pszStart = pszSQLCommand;
     389             :                     }
     390             :                     else
     391           4 :                         OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand,
     392             :                                            oSetLayers, osModifiedSQL);
     393             :                 }
     394             :                 else
     395           4 :                     break;
     396         337 :             }
     397             :         }
     398       23246 :         else if (STARTS_WITH_CI(pszSQLCommand, "JOIN") &&
     399           9 :                  isspace(
     400           9 :                      static_cast<unsigned char>(pszSQLCommand[strlen("JOIN")])))
     401             :         {
     402           5 :             pszSQLCommand += strlen("JOIN") + 1;
     403           5 :             OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers,
     404             :                                osModifiedSQL);
     405             :         }
     406       23241 :         else if (STARTS_WITH_CI(pszSQLCommand, "INTO") &&
     407          12 :                  isspace(
     408          12 :                      static_cast<unsigned char>(pszSQLCommand[strlen("INTO")])))
     409             :         {
     410          12 :             pszSQLCommand += strlen("INTO") + 1;
     411          12 :             OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers,
     412             :                                osModifiedSQL);
     413             :         }
     414       23229 :         else if (STARTS_WITH_CI(pszSQLCommand, "UPDATE") &&
     415           8 :                  isspace(static_cast<unsigned char>(
     416           8 :                      pszSQLCommand[strlen("UPDATE")])))
     417             :         {
     418           8 :             pszSQLCommand += strlen("UPDATE") + 1;
     419           8 :             OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers,
     420             :                                osModifiedSQL);
     421             :         }
     422             :         else
     423       23221 :             pszSQLCommand++;
     424             :     }
     425             : 
     426         639 :     CPLString osTruncated(pszStart);
     427         639 :     osTruncated.resize(pszSQLCommand - pszStart);
     428         639 :     osModifiedSQL += osTruncated;
     429             : 
     430         639 :     *ppszSQLCommand = pszSQLCommand;
     431         639 : }
     432             : 
     433         637 : static void OGR2SQLITEGetPotentialLayerNames(
     434             :     const char *pszSQLCommand, std::set<LayerDesc> &oSetLayers,
     435             :     std::set<CPLString> &oSetSpatialIndex, CPLString &osModifiedSQL)
     436             : {
     437         637 :     int nNum = 1;
     438         637 :     OGR2SQLITEGetPotentialLayerNamesInternal(
     439             :         &pszSQLCommand, oSetLayers, oSetSpatialIndex, osModifiedSQL, nNum);
     440         637 : }
     441             : 
     442             : /************************************************************************/
     443             : /*                   OGRSQLiteGetReferencedLayers()                     */
     444             : /************************************************************************/
     445             : 
     446           1 : std::set<LayerDesc> OGRSQLiteGetReferencedLayers(const char *pszStatement)
     447             : {
     448             :     /* -------------------------------------------------------------------- */
     449             :     /*      Analyze the statement to determine which tables will be used.   */
     450             :     /* -------------------------------------------------------------------- */
     451           1 :     std::set<LayerDesc> oSetLayers;
     452           2 :     std::set<CPLString> oSetSpatialIndex;
     453           2 :     CPLString osModifiedSQL;
     454           1 :     OGR2SQLITEGetPotentialLayerNames(pszStatement, oSetLayers, oSetSpatialIndex,
     455             :                                      osModifiedSQL);
     456             : 
     457           2 :     return oSetLayers;
     458             : }
     459             : 
     460             : #ifndef HAVE_SQLITE3EXT_H
     461             : OGRLayer *OGRSQLiteExecuteSQL(GDALDataset *, const char *, OGRGeometry *,
     462             :                               const char *)
     463             : {
     464             :     CPLError(CE_Failure, CPLE_NotSupported,
     465             :              "SQL SQLite dialect not supported due to GDAL being built "
     466             :              "without sqlite3ext.h header");
     467             :     return nullptr;
     468             : }
     469             : 
     470             : #else
     471             : 
     472             : /************************************************************************/
     473             : /*                       OGRSQLiteExecuteSQLLayer                       */
     474             : /************************************************************************/
     475             : 
     476             : class OGRSQLiteExecuteSQLLayer final : public OGRSQLiteSelectLayer
     477             : {
     478             :     char *m_pszTmpDBName = nullptr;
     479             :     bool m_bStringsAsUTF8 = false;
     480             : 
     481             :     CPL_DISALLOW_COPY_ASSIGN(OGRSQLiteExecuteSQLLayer)
     482             : 
     483             :   public:
     484             :     OGRSQLiteExecuteSQLLayer(char *pszTmpDBName, OGRSQLiteDataSource *poDS,
     485             :                              const CPLString &osSQL, sqlite3_stmt *hStmt,
     486             :                              bool bUseStatementForGetNextFeature,
     487             :                              bool bEmptyLayer, bool bCanReopenBaseDS,
     488             :                              bool bStringsAsUTF8);
     489             :     virtual ~OGRSQLiteExecuteSQLLayer();
     490             : 
     491             :     int TestCapability(const char *pszCap) override;
     492             : };
     493             : 
     494             : /************************************************************************/
     495             : /*                         OGRSQLiteExecuteSQLLayer()                   */
     496             : /************************************************************************/
     497             : 
     498         595 : OGRSQLiteExecuteSQLLayer::OGRSQLiteExecuteSQLLayer(
     499             :     char *pszTmpDBNameIn, OGRSQLiteDataSource *poDSIn, const CPLString &osSQL,
     500             :     sqlite3_stmt *hStmtIn, bool bUseStatementForGetNextFeature,
     501         595 :     bool bEmptyLayer, bool bCanReopenBaseDS, bool bStringsAsUTF8)
     502             :     : OGRSQLiteSelectLayer(poDSIn, osSQL, hStmtIn,
     503             :                            bUseStatementForGetNextFeature, bEmptyLayer, true,
     504             :                            bCanReopenBaseDS),
     505         595 :       m_pszTmpDBName(pszTmpDBNameIn), m_bStringsAsUTF8(bStringsAsUTF8)
     506             : {
     507         595 : }
     508             : 
     509             : /************************************************************************/
     510             : /*                        ~OGRSQLiteExecuteSQLLayer()                   */
     511             : /************************************************************************/
     512             : 
     513        1188 : OGRSQLiteExecuteSQLLayer::~OGRSQLiteExecuteSQLLayer()
     514             : {
     515             :     // This is a bit peculiar: we must "finalize" the OGRLayer, since
     516             :     // it has objects that depend on the datasource, that we are just
     517             :     // going to destroy afterwards. The issue here is that we destroy
     518             :     // our own datasource,
     519         594 :     Finalize();
     520             : 
     521         594 :     delete m_poDS;
     522         594 :     VSIUnlink(m_pszTmpDBName);
     523         594 :     CPLFree(m_pszTmpDBName);
     524        1188 : }
     525             : 
     526             : /************************************************************************/
     527             : /*                           TestCapability()                           */
     528             : /************************************************************************/
     529             : 
     530           1 : int OGRSQLiteExecuteSQLLayer::TestCapability(const char *pszCap)
     531             : {
     532           1 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
     533           1 :         return m_bStringsAsUTF8;
     534           0 :     return OGRSQLiteSelectLayer::TestCapability(pszCap);
     535             : }
     536             : 
     537             : /************************************************************************/
     538             : /*               OGR2SQLITE_IgnoreAllFieldsExceptGeometry()             */
     539             : /************************************************************************/
     540             : 
     541             : #ifdef HAVE_SPATIALITE
     542           2 : static void OGR2SQLITE_IgnoreAllFieldsExceptGeometry(OGRLayer *poLayer)
     543             : {
     544           2 :     char **papszIgnored = nullptr;
     545           2 :     papszIgnored = CSLAddString(papszIgnored, "OGR_STYLE");
     546           2 :     OGRFeatureDefn *poFeatureDefn = poLayer->GetLayerDefn();
     547           4 :     for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
     548             :     {
     549           2 :         papszIgnored = CSLAddString(
     550           2 :             papszIgnored, poFeatureDefn->GetFieldDefn(i)->GetNameRef());
     551             :     }
     552           2 :     poLayer->SetIgnoredFields(const_cast<const char **>(papszIgnored));
     553           2 :     CSLDestroy(papszIgnored);
     554           2 : }
     555             : #endif
     556             : 
     557             : /************************************************************************/
     558             : /*                  OGR2SQLITEDealWithSpatialColumn()                   */
     559             : /************************************************************************/
     560             : #if HAVE_SPATIALITE
     561             : #define WHEN_SPATIALITE(arg) arg
     562             : #else
     563             : #define WHEN_SPATIALITE(arg)
     564             : #endif
     565             : 
     566         251 : static int OGR2SQLITEDealWithSpatialColumn(
     567             :     OGRLayer *poLayer, int iGeomCol, const LayerDesc &oLayerDesc,
     568             :     const CPLString &osTableName, OGRSQLiteDataSource *poSQLiteDS, sqlite3 *hDB,
     569             :     bool bSpatialiteDB, const std::set<LayerDesc> &WHEN_SPATIALITE(oSetLayers),
     570             :     const std::set<CPLString> &WHEN_SPATIALITE(oSetSpatialIndex))
     571             : {
     572             :     OGRGeomFieldDefn *poGeomField =
     573         251 :         poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeomCol);
     574         502 :     CPLString osGeomColRaw;
     575         251 :     if (iGeomCol == 0)
     576         246 :         osGeomColRaw = OGR2SQLITE_GetNameForGeometryColumn(poLayer);
     577             :     else
     578           5 :         osGeomColRaw = poGeomField->GetNameRef();
     579         251 :     const char *pszGeomColRaw = osGeomColRaw.c_str();
     580             : 
     581         502 :     CPLString osGeomColEscaped(SQLEscapeLiteral(pszGeomColRaw));
     582         251 :     const char *pszGeomColEscaped = osGeomColEscaped.c_str();
     583             : 
     584         502 :     CPLString osLayerNameEscaped(SQLEscapeLiteral(osTableName));
     585         251 :     const char *pszLayerNameEscaped = osLayerNameEscaped.c_str();
     586             : 
     587             :     CPLString osIdxNameRaw(
     588         502 :         CPLSPrintf("idx_%s_%s", oLayerDesc.osLayerName.c_str(), pszGeomColRaw));
     589         502 :     CPLString osIdxNameEscaped(SQLEscapeName(osIdxNameRaw));
     590             : 
     591             :     /* Make sure that the SRS is injected in spatial_ref_sys */
     592         251 :     const OGRSpatialReference *poSRS = poGeomField->GetSpatialRef();
     593         251 :     if (iGeomCol == 0 && poSRS == nullptr)
     594         221 :         poSRS = poLayer->GetSpatialRef();
     595         251 :     int nSRSId = poSQLiteDS->GetUndefinedSRID();
     596         251 :     if (poSRS != nullptr)
     597          30 :         nSRSId = poSQLiteDS->FetchSRSId(poSRS);
     598             : 
     599         502 :     CPLString osSQL;
     600             : #ifdef HAVE_SPATIALITE
     601         251 :     bool bCreateSpatialIndex = false;
     602             : #endif
     603         251 :     if (!bSpatialiteDB)
     604             :     {
     605             :         osSQL.Printf("INSERT INTO geometry_columns (f_table_name, "
     606             :                      "f_geometry_column, geometry_format, geometry_type, "
     607             :                      "coord_dimension, srid) "
     608             :                      "VALUES ('%s','%s','SpatiaLite',%d,%d,%d)",
     609             :                      pszLayerNameEscaped, pszGeomColEscaped,
     610          58 :                      static_cast<int>(wkbFlatten(poLayer->GetGeomType())),
     611         116 :                      wkbHasZ(poLayer->GetGeomType()) ? 3 : 2, nSRSId);
     612             :     }
     613             : #ifdef HAVE_SPATIALITE
     614             :     else
     615             :     {
     616             :         /* We detect the need for creating a spatial index by 2 means : */
     617             : 
     618             :         /* 1) if there's an explicit reference to a
     619             :          * 'idx_layername_geometrycolumn' */
     620             :         /*   table in the SQL --> old/traditional way of requesting spatial
     621             :          * indices */
     622             :         /*   with spatialite. */
     623             : 
     624         193 :         std::set<LayerDesc>::const_iterator oIter2 = oSetLayers.begin();
     625         392 :         for (; oIter2 != oSetLayers.end(); ++oIter2)
     626             :         {
     627         200 :             const LayerDesc &oLayerDescIter = *oIter2;
     628         200 :             if (EQUAL(oLayerDescIter.osLayerName, osIdxNameRaw))
     629             :             {
     630           1 :                 bCreateSpatialIndex = true;
     631           1 :                 break;
     632             :             }
     633             :         }
     634             : 
     635             :         /* 2) or if there's a SELECT FROM SpatialIndex WHERE f_table_name =
     636             :          * 'layername' */
     637         193 :         if (!bCreateSpatialIndex)
     638             :         {
     639             :             std::set<CPLString>::const_iterator oIter3 =
     640         192 :                 oSetSpatialIndex.begin();
     641         193 :             for (; oIter3 != oSetSpatialIndex.end(); ++oIter3)
     642             :             {
     643           2 :                 const CPLString &osNameIter = *oIter3;
     644           2 :                 if (EQUAL(osNameIter, oLayerDesc.osLayerName))
     645             :                 {
     646           1 :                     bCreateSpatialIndex = true;
     647           1 :                     break;
     648             :                 }
     649             :             }
     650             :         }
     651             : 
     652         193 :         if (poSQLiteDS->HasSpatialite4Layout())
     653             :         {
     654         193 :             const auto eGeomType = poLayer->GetGeomType();
     655         193 :             int nGeomType = eGeomType;
     656         193 :             int nCoordDimension = 2;
     657         193 :             if (wkbHasZ(eGeomType))
     658             :             {
     659           1 :                 nGeomType += 1000;
     660           1 :                 nCoordDimension = 3;
     661             :             }
     662             : 
     663             :             osSQL.Printf("INSERT INTO geometry_columns (f_table_name, "
     664             :                          "f_geometry_column, geometry_type, coord_dimension, "
     665             :                          "srid, spatial_index_enabled) "
     666             :                          "VALUES (Lower('%s'),Lower('%s'),%d ,%d ,%d, %d)",
     667             :                          pszLayerNameEscaped, pszGeomColEscaped, nGeomType,
     668             :                          nCoordDimension, nSRSId,
     669         193 :                          static_cast<int>(bCreateSpatialIndex));
     670             :         }
     671             :         else
     672             :         {
     673             :             const char *pszGeometryType =
     674           0 :                 OGRToOGCGeomType(poLayer->GetGeomType());
     675           0 :             if (pszGeometryType[0] == '\0')
     676           0 :                 pszGeometryType = "GEOMETRY";
     677             : 
     678             :             osSQL.Printf("INSERT INTO geometry_columns (f_table_name, "
     679             :                          "f_geometry_column, type, coord_dimension, "
     680             :                          "srid, spatial_index_enabled) "
     681             :                          "VALUES ('%s','%s','%s','%s',%d, %d)",
     682             :                          pszLayerNameEscaped, pszGeomColEscaped,
     683             :                          pszGeometryType,
     684           0 :                          wkbHasZ(poLayer->GetGeomType()) ? "XYZ" : "XY", nSRSId,
     685           0 :                          static_cast<int>(bCreateSpatialIndex));
     686             :         }
     687             :     }
     688             : #endif  // HAVE_SPATIALITE
     689         251 :     char *pszErrMsg = nullptr;
     690         251 :     int rc = sqlite3_exec(hDB, osSQL.c_str(), nullptr, nullptr, &pszErrMsg);
     691         251 :     if (pszErrMsg != nullptr)
     692             :     {
     693           2 :         CPLDebug("SQLITE", "%s -> %s", osSQL.c_str(), pszErrMsg);
     694           2 :         sqlite3_free(pszErrMsg);
     695             :     }
     696             : 
     697             : #ifdef HAVE_SPATIALITE
     698             :     /* -------------------------------------------------------------------- */
     699             :     /*      Should we create a spatial index ?.                             */
     700             :     /* -------------------------------------------------------------------- */
     701         251 :     if (!bSpatialiteDB || !bCreateSpatialIndex)
     702         249 :         return rc == SQLITE_OK;
     703             : 
     704           2 :     CPLDebug("SQLITE", "Create spatial index %s", osIdxNameRaw.c_str());
     705             : 
     706             :     /* ENABLE_VIRTUAL_OGR_SPATIAL_INDEX is not defined */
     707             : #ifdef ENABLE_VIRTUAL_OGR_SPATIAL_INDEX
     708             :     osSQL.Printf(
     709             :         "CREATE VIRTUAL TABLE \"%s\" USING "
     710             :         "VirtualOGRSpatialIndex(%d, '%s', pkid, xmin, xmax, ymin, ymax)",
     711             :         osIdxNameEscaped.c_str(), nExtraDS,
     712             :         SQLEscapeLiteral(oLayerDesc.osLayerName).c_str());
     713             : 
     714             :     rc = sqlite3_exec(hDB, osSQL.c_str(), NULL, NULL, NULL);
     715             :     if (rc != SQLITE_OK)
     716             :     {
     717             :         CPLDebug("SQLITE", "Error occurred during spatial index creation : %s",
     718             :                  sqlite3_errmsg(hDB));
     719             :     }
     720             : #else   //  ENABLE_VIRTUAL_OGR_SPATIAL_INDEX
     721           2 :     rc = sqlite3_exec(hDB, "BEGIN", nullptr, nullptr, nullptr);
     722             : 
     723             :     osSQL.Printf("CREATE VIRTUAL TABLE \"%s\" "
     724             :                  "USING rtree(pkid, xmin, xmax, ymin, ymax)",
     725           2 :                  osIdxNameEscaped.c_str());
     726             : 
     727           2 :     if (rc == SQLITE_OK)
     728           2 :         rc = sqlite3_exec(hDB, osSQL.c_str(), nullptr, nullptr, nullptr);
     729             : 
     730           2 :     sqlite3_stmt *hStmt = nullptr;
     731           2 :     if (rc == SQLITE_OK)
     732             :     {
     733             :         const char *pszInsertInto =
     734           2 :             CPLSPrintf("INSERT INTO \"%s\" (pkid, xmin, xmax, ymin, ymax) "
     735             :                        "VALUES (?,?,?,?,?)",
     736             :                        osIdxNameEscaped.c_str());
     737           2 :         rc = sqlite3_prepare_v2(hDB, pszInsertInto, -1, &hStmt, nullptr);
     738             :     }
     739             : 
     740           2 :     OGR2SQLITE_IgnoreAllFieldsExceptGeometry(poLayer);
     741           2 :     poLayer->ResetReading();
     742             : 
     743           2 :     OGRFeature *poFeature = nullptr;
     744           2 :     OGREnvelope sEnvelope;
     745          12 :     while (rc == SQLITE_OK &&
     746           6 :            (poFeature = poLayer->GetNextFeature()) != nullptr)
     747             :     {
     748           4 :         OGRGeometry *poGeom = poFeature->GetGeometryRef();
     749           4 :         if (poGeom != nullptr && !poGeom->IsEmpty())
     750             :         {
     751           4 :             poGeom->getEnvelope(&sEnvelope);
     752           4 :             sqlite3_bind_int64(hStmt, 1,
     753           4 :                                static_cast<sqlite3_int64>(poFeature->GetFID()));
     754           4 :             sqlite3_bind_double(hStmt, 2, sEnvelope.MinX);
     755           4 :             sqlite3_bind_double(hStmt, 3, sEnvelope.MaxX);
     756           4 :             sqlite3_bind_double(hStmt, 4, sEnvelope.MinY);
     757           4 :             sqlite3_bind_double(hStmt, 5, sEnvelope.MaxY);
     758           4 :             rc = sqlite3_step(hStmt);
     759           4 :             if (rc == SQLITE_OK || rc == SQLITE_DONE)
     760           4 :                 rc = sqlite3_reset(hStmt);
     761             :         }
     762           4 :         delete poFeature;
     763             :     }
     764             : 
     765           2 :     poLayer->SetIgnoredFields(nullptr);
     766             : 
     767           2 :     sqlite3_finalize(hStmt);
     768             : 
     769           2 :     if (rc == SQLITE_OK)
     770           2 :         rc = sqlite3_exec(hDB, "COMMIT", nullptr, nullptr, nullptr);
     771             :     else
     772             :     {
     773           0 :         CPLDebug("SQLITE", "Error occurred during spatial index creation : %s",
     774             :                  sqlite3_errmsg(hDB));
     775           0 :         rc = sqlite3_exec(hDB, "ROLLBACK", nullptr, nullptr, nullptr);
     776             :     }
     777             : #endif  //  ENABLE_VIRTUAL_OGR_SPATIAL_INDEX
     778             : 
     779             : #endif  // HAVE_SPATIALITE
     780             : 
     781           2 :     return rc == SQLITE_OK;
     782             : }
     783             : 
     784             : /************************************************************************/
     785             : /*                          OGRSQLiteExecuteSQL()                       */
     786             : /************************************************************************/
     787             : 
     788         643 : OGRLayer *OGRSQLiteExecuteSQL(GDALDataset *poDS, const char *pszStatement,
     789             :                               OGRGeometry *poSpatialFilter,
     790             :                               CPL_UNUSED const char *pszDialect)
     791             : {
     792         643 :     while (*pszStatement != '\0' &&
     793         643 :            isspace(static_cast<unsigned char>(*pszStatement)))
     794           0 :         pszStatement++;
     795             : 
     796         643 :     if (STARTS_WITH_CI(pszStatement, "ALTER TABLE ") ||
     797         642 :         STARTS_WITH_CI(pszStatement, "DROP TABLE ") ||
     798         641 :         STARTS_WITH_CI(pszStatement, "CREATE INDEX ") ||
     799         640 :         STARTS_WITH_CI(pszStatement, "DROP INDEX "))
     800             :     {
     801           4 :         CPLError(CE_Failure, CPLE_NotSupported,
     802             :                  "SQL command not supported with SQLite dialect. "
     803             :                  "Use OGRSQL dialect instead.");
     804           4 :         return nullptr;
     805             :     }
     806         647 :     else if (STARTS_WITH_CI(pszStatement, "CREATE VIRTUAL TABLE ") &&
     807           8 :              CPLTestBool(CPLGetConfigOption(
     808             :                  "OGR_SQLITE_DIALECT_ALLOW_CREATE_VIRTUAL_TABLE", "NO")))
     809             :     {
     810             :         // for ogr_virtualogr.py::ogr_virtualogr_run_sql() only. This is
     811             :         // just a convenient way of testing VirtualOGR() with
     812             :         // CREATE VIRTUAL TABLE ... USING VirtualOGR(...)
     813             :         // but there is no possible use of that given we run that into
     814             :         // an ephemeral database.
     815             :     }
     816             :     else
     817             :     {
     818         632 :         bool bUnderstoodStatement = false;
     819         134 :         for (const char *pszKeyword : {"SELECT", "WITH", "EXPLAIN", "INSERT",
     820         766 :                                        "UPDATE", "DELETE", "REPLACE"})
     821             :         {
     822         763 :             if (STARTS_WITH_CI(pszStatement, pszKeyword) &&
     823         629 :                 std::isspace(static_cast<unsigned char>(
     824         629 :                     pszStatement[strlen(pszKeyword)])))
     825             :             {
     826         629 :                 bUnderstoodStatement = true;
     827         629 :                 break;
     828             :             }
     829             :         }
     830         632 :         if (!bUnderstoodStatement)
     831             :         {
     832           3 :             CPLError(CE_Failure, CPLE_NotSupported, "Unsupported SQL command.");
     833           3 :             return nullptr;
     834             :         }
     835             :     }
     836             : 
     837         636 :     char *pszTmpDBName = static_cast<char *>(CPLMalloc(256));
     838         636 :     snprintf(pszTmpDBName, 256, "%s", VSIMemGenerateHiddenFilename("temp.db"));
     839             : 
     840         636 :     OGRSQLiteDataSource *poSQLiteDS = nullptr;
     841         636 :     bool bSpatialiteDB = false;
     842             : 
     843             :     /* -------------------------------------------------------------------- */
     844             :     /*      Create in-memory sqlite/spatialite DB                           */
     845             :     /* -------------------------------------------------------------------- */
     846             : 
     847             : #ifdef HAVE_SPATIALITE
     848             : 
     849             : /* -------------------------------------------------------------------- */
     850             : /*      Creating an empty SpatiaLite DB (with spatial_ref_sys populated */
     851             : /*      has a significant cost. So at the first attempt, let's make     */
     852             : /*      one and cache it for later use.                                 */
     853             : /* -------------------------------------------------------------------- */
     854             : #if 1
     855             :     static size_t nEmptyDBSize = 0;
     856             :     static GByte *pabyEmptyDB = nullptr;
     857             :     {
     858             :         static CPLMutex *hMutex = nullptr;
     859        1272 :         CPLMutexHolder oMutexHolder(&hMutex);
     860             :         static bool bTried = false;
     861         636 :         if (!bTried && CPLTestBool(CPLGetConfigOption(
     862             :                            "OGR_SQLITE_DIALECT_USE_SPATIALITE", "YES")))
     863             :         {
     864           3 :             bTried = true;
     865           3 :             char *pszCachedFilename = static_cast<char *>(CPLMalloc(256));
     866           3 :             snprintf(pszCachedFilename, 256, "%s",
     867             :                      VSIMemGenerateHiddenFilename("reference.db"));
     868           3 :             char **papszOptions = CSLAddString(nullptr, "SPATIALITE=YES");
     869           3 :             OGRSQLiteDataSource *poCachedDS = new OGRSQLiteDataSource();
     870             :             const int nRet =
     871           3 :                 poCachedDS->Create(pszCachedFilename, papszOptions);
     872           3 :             CSLDestroy(papszOptions);
     873           3 :             papszOptions = nullptr;
     874           3 :             delete poCachedDS;
     875           3 :             if (nRet)
     876             :             {
     877             :                 /* Note: the reference file keeps the ownership of the data, so
     878             :                  * that */
     879             :                 /* it gets released with VSICleanupFileManager() */
     880           3 :                 vsi_l_offset nEmptyDBSizeLarge = 0;
     881           3 :                 pabyEmptyDB = VSIGetMemFileBuffer(pszCachedFilename,
     882             :                                                   &nEmptyDBSizeLarge, FALSE);
     883           3 :                 nEmptyDBSize = static_cast<size_t>(nEmptyDBSizeLarge);
     884             :             }
     885           3 :             CPLFree(pszCachedFilename);
     886             :         }
     887             :     }
     888             : 
     889             :     /* The following configuration option is useful mostly for debugging/testing
     890             :      */
     891        1272 :     if (pabyEmptyDB != nullptr &&
     892         636 :         CPLTestBool(
     893             :             CPLGetConfigOption("OGR_SQLITE_DIALECT_USE_SPATIALITE", "YES")))
     894             :     {
     895             :         GByte *pabyEmptyDBClone =
     896         526 :             static_cast<GByte *>(VSI_MALLOC_VERBOSE(nEmptyDBSize));
     897         526 :         if (pabyEmptyDBClone == nullptr)
     898             :         {
     899           0 :             CPLFree(pszTmpDBName);
     900           0 :             return nullptr;
     901             :         }
     902         526 :         memcpy(pabyEmptyDBClone, pabyEmptyDB, nEmptyDBSize);
     903         526 :         VSIFCloseL(VSIFileFromMemBuffer(pszTmpDBName, pabyEmptyDBClone,
     904             :                                         nEmptyDBSize, TRUE));
     905             : 
     906         526 :         poSQLiteDS = new OGRSQLiteDataSource();
     907         526 :         GDALOpenInfo oOpenInfo(pszTmpDBName, GDAL_OF_VECTOR | GDAL_OF_UPDATE);
     908             :         CPLConfigOptionSetter oSetter("OGR_SQLITE_STATIC_VIRTUAL_OGR", "NO",
     909         526 :                                       false);
     910         526 :         const int nRet = poSQLiteDS->Open(&oOpenInfo);
     911         526 :         if (!nRet)
     912             :         {
     913             :             /* should not happen really ! */
     914           0 :             delete poSQLiteDS;
     915           0 :             VSIUnlink(pszTmpDBName);
     916           0 :             CPLFree(pszTmpDBName);
     917           0 :             return nullptr;
     918             :         }
     919         526 :         bSpatialiteDB = true;
     920             :     }
     921             : #else
     922             :     /* No caching version */
     923             :     poSQLiteDS = new OGRSQLiteDataSource();
     924             :     char **papszOptions = CSLAddString(NULL, "SPATIALITE=YES");
     925             :     {
     926             :         CPLConfigOptionSetter oSetter("OGR_SQLITE_STATIC_VIRTUAL_OGR", "NO",
     927             :                                       false);
     928             :         const int nRet = poSQLiteDS->Create(pszTmpDBName, papszOptions);
     929             :         CSLDestroy(papszOptions);
     930             :         papszOptions = nullptr;
     931             :         if (nRet)
     932             :         {
     933             :             bSpatialiteDB = true;
     934             :         }
     935             :     }
     936             : #endif
     937             : 
     938             :     else
     939             :     {
     940         110 :         delete poSQLiteDS;
     941         110 :         poSQLiteDS = nullptr;
     942             : #else   // HAVE_SPATIALITE
     943             :     if (true)
     944             :     {
     945             : #endif  // HAVE_SPATIALITE
     946             : 
     947             :         // cppcheck-suppress redundantAssignment
     948         110 :         poSQLiteDS = new OGRSQLiteDataSource();
     949             :         CPLConfigOptionSetter oSetter("OGR_SQLITE_STATIC_VIRTUAL_OGR", "NO",
     950         110 :                                       false);
     951         110 :         const int nRet = poSQLiteDS->Create(pszTmpDBName, nullptr);
     952         110 :         if (!nRet)
     953             :         {
     954           0 :             delete poSQLiteDS;
     955           0 :             VSIUnlink(pszTmpDBName);
     956           0 :             CPLFree(pszTmpDBName);
     957           0 :             return nullptr;
     958             :         }
     959             :     }
     960             : 
     961             :     /* -------------------------------------------------------------------- */
     962             :     /*      Attach the Virtual Table OGR2SQLITE module to it.               */
     963             :     /* -------------------------------------------------------------------- */
     964         636 :     OGR2SQLITEModule *poModule = OGR2SQLITE_Setup(poDS, poSQLiteDS);
     965         636 :     if (!poModule)
     966             :     {
     967           0 :         delete poSQLiteDS;
     968           0 :         VSIUnlink(pszTmpDBName);
     969           0 :         CPLFree(pszTmpDBName);
     970           0 :         return nullptr;
     971             :     }
     972         636 :     sqlite3 *hDB = poSQLiteDS->GetDB();
     973             : 
     974             :     /* -------------------------------------------------------------------- */
     975             :     /*      Analysze the statement to determine which tables will be used.  */
     976             :     /* -------------------------------------------------------------------- */
     977        1272 :     std::set<LayerDesc> oSetLayers;
     978        1272 :     std::set<CPLString> oSetSpatialIndex;
     979        1272 :     CPLString osModifiedSQL;
     980         636 :     OGR2SQLITEGetPotentialLayerNames(pszStatement, oSetLayers, oSetSpatialIndex,
     981             :                                      osModifiedSQL);
     982         636 :     std::set<LayerDesc>::iterator oIter = oSetLayers.begin();
     983             : 
     984         636 :     if (strcmp(pszStatement, osModifiedSQL.c_str()) != 0)
     985           6 :         CPLDebug("OGR", "Modified SQL: %s", osModifiedSQL.c_str());
     986         636 :     pszStatement = osModifiedSQL.c_str(); /* do not use it anymore */
     987             : 
     988             :     const bool bFoundOGRStyle =
     989         636 :         (osModifiedSQL.ifind("OGR_STYLE") != std::string::npos);
     990             : 
     991             :     /* -------------------------------------------------------------------- */
     992             :     /*      For each of those tables, create a Virtual Table.               */
     993             :     /* -------------------------------------------------------------------- */
     994         636 :     OGRLayer *poSingleSrcLayer = nullptr;
     995         636 :     bool bStringsAsUTF8 = true;
     996        1005 :     for (; oIter != oSetLayers.end(); ++oIter)
     997             :     {
     998         371 :         const LayerDesc &oLayerDesc = *oIter;
     999             :         /*CPLDebug("OGR", "Layer desc : %s, %s, %s, %s",
    1000             :                  oLayerDesc.osOriginalStr.c_str(),
    1001             :                  oLayerDesc.osSubstitutedName.c_str(),
    1002             :                  oLayerDesc.osDSName.c_str(),
    1003             :                  oLayerDesc.osLayerName.c_str());*/
    1004             : 
    1005         371 :         CPLString osSQL;
    1006         371 :         OGRLayer *poLayer = nullptr;
    1007         371 :         CPLString osTableName;
    1008         371 :         int nExtraDS = -1;
    1009         371 :         if (oLayerDesc.osDSName.empty())
    1010             :         {
    1011         364 :             poLayer = poDS->GetLayerByName(oLayerDesc.osLayerName);
    1012             :             /* Might be a false positive (unlikely) */
    1013         364 :             if (poLayer == nullptr)
    1014           8 :                 continue;
    1015             : 
    1016         356 :             osTableName = oLayerDesc.osLayerName;
    1017             :         }
    1018             :         else
    1019             :         {
    1020             :             auto poOtherDS = std::unique_ptr<GDALDataset>(
    1021             :                 GDALDataset::Open(oLayerDesc.osDSName, GDAL_OF_VECTOR, nullptr,
    1022           7 :                                   nullptr, nullptr));
    1023           7 :             if (poOtherDS == nullptr)
    1024             :             {
    1025           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1026             :                          "Cannot open datasource '%s'",
    1027             :                          oLayerDesc.osDSName.c_str());
    1028           1 :                 delete poSQLiteDS;
    1029           1 :                 VSIUnlink(pszTmpDBName);
    1030           1 :                 CPLFree(pszTmpDBName);
    1031           1 :                 return nullptr;
    1032             :             }
    1033             : 
    1034           6 :             poLayer = poOtherDS->GetLayerByName(oLayerDesc.osLayerName);
    1035           6 :             if (poLayer == nullptr)
    1036             :             {
    1037           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1038             :                          "Cannot find layer '%s' in '%s'",
    1039             :                          oLayerDesc.osLayerName.c_str(),
    1040             :                          oLayerDesc.osDSName.c_str());
    1041           1 :                 delete poSQLiteDS;
    1042           1 :                 VSIUnlink(pszTmpDBName);
    1043           1 :                 CPLFree(pszTmpDBName);
    1044           1 :                 return nullptr;
    1045             :             }
    1046             : 
    1047           5 :             osTableName = oLayerDesc.osSubstitutedName;
    1048             : 
    1049           5 :             nExtraDS = OGR2SQLITE_AddExtraDS(poModule, poOtherDS.release());
    1050             :         }
    1051             : 
    1052         361 :         if (!poLayer->TestCapability(OLCStringsAsUTF8))
    1053         348 :             bStringsAsUTF8 = false;
    1054             : 
    1055         361 :         if (oSetLayers.size() == 1)
    1056         347 :             poSingleSrcLayer = poLayer;
    1057             : 
    1058             :         osSQL.Printf(
    1059             :             "CREATE VIRTUAL TABLE \"%s\" USING VirtualOGR(%d,'%s',%d,%d)",
    1060         722 :             SQLEscapeName(osTableName).c_str(), nExtraDS,
    1061         722 :             SQLEscapeLiteral(oLayerDesc.osLayerName).c_str(),
    1062        1083 :             bFoundOGRStyle ? 1 : 0, TRUE /*bExposeOGRNativeData*/);
    1063             : 
    1064         361 :         char *pszErrMsg = nullptr;
    1065         361 :         int rc = sqlite3_exec(hDB, osSQL.c_str(), nullptr, nullptr, &pszErrMsg);
    1066         361 :         if (rc != SQLITE_OK)
    1067             :         {
    1068           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1069             :                      "Cannot create virtual table for layer '%s' : %s",
    1070             :                      osTableName.c_str(), pszErrMsg);
    1071           0 :             sqlite3_free(pszErrMsg);
    1072           0 :             continue;
    1073             :         }
    1074             : 
    1075         612 :         for (int i = 0; i < poLayer->GetLayerDefn()->GetGeomFieldCount(); i++)
    1076             :         {
    1077         251 :             OGR2SQLITEDealWithSpatialColumn(poLayer, i, oLayerDesc, osTableName,
    1078             :                                             poSQLiteDS, hDB, bSpatialiteDB,
    1079             :                                             oSetLayers, oSetSpatialIndex);
    1080             :         }
    1081             :     }
    1082             : 
    1083             :     /* -------------------------------------------------------------------- */
    1084             :     /*      Reload, so that virtual tables are recognized                   */
    1085             :     /* -------------------------------------------------------------------- */
    1086         634 :     poSQLiteDS->ReloadLayers();
    1087             : 
    1088             :     /* -------------------------------------------------------------------- */
    1089             :     /*      Prepare the statement.                                          */
    1090             :     /* -------------------------------------------------------------------- */
    1091             :     /* This will speed-up layer creation */
    1092             :     /* ORDER BY are costly to evaluate and are not necessary to establish */
    1093             :     /* the layer definition. */
    1094         634 :     bool bUseStatementForGetNextFeature = true;
    1095         634 :     bool bEmptyLayer = false;
    1096             : 
    1097         634 :     sqlite3_stmt *hSQLStmt = nullptr;
    1098         634 :     int rc = sqlite3_prepare_v2(hDB, pszStatement, -1, &hSQLStmt, nullptr);
    1099             : 
    1100         634 :     if (rc != SQLITE_OK)
    1101             :     {
    1102           3 :         CPLError(CE_Failure, CPLE_AppDefined,
    1103             :                  "In ExecuteSQL(): sqlite3_prepare_v2(%s):\n  %s", pszStatement,
    1104             :                  sqlite3_errmsg(hDB));
    1105             : 
    1106           3 :         if (hSQLStmt != nullptr)
    1107             :         {
    1108           0 :             sqlite3_finalize(hSQLStmt);
    1109             :         }
    1110             : 
    1111           3 :         delete poSQLiteDS;
    1112           3 :         VSIUnlink(pszTmpDBName);
    1113           3 :         CPLFree(pszTmpDBName);
    1114             : 
    1115           3 :         return nullptr;
    1116             :     }
    1117             : 
    1118             :     /* -------------------------------------------------------------------- */
    1119             :     /*      Do we get a resultset?                                          */
    1120             :     /* -------------------------------------------------------------------- */
    1121         631 :     rc = sqlite3_step(hSQLStmt);
    1122         631 :     if (rc != SQLITE_ROW)
    1123             :     {
    1124         161 :         if (rc != SQLITE_DONE)
    1125             :         {
    1126           1 :             CPLError(CE_Failure, CPLE_AppDefined,
    1127             :                      "In ExecuteSQL(): sqlite3_step(%s):\n  %s", pszStatement,
    1128             :                      sqlite3_errmsg(hDB));
    1129             : 
    1130           1 :             sqlite3_finalize(hSQLStmt);
    1131             : 
    1132           1 :             delete poSQLiteDS;
    1133           1 :             VSIUnlink(pszTmpDBName);
    1134           1 :             CPLFree(pszTmpDBName);
    1135             : 
    1136           1 :             return nullptr;
    1137             :         }
    1138             : 
    1139         160 :         if (!STARTS_WITH_CI(pszStatement, "SELECT "))
    1140             :         {
    1141             : 
    1142          35 :             sqlite3_finalize(hSQLStmt);
    1143             : 
    1144          35 :             delete poSQLiteDS;
    1145          35 :             VSIUnlink(pszTmpDBName);
    1146          35 :             CPLFree(pszTmpDBName);
    1147             : 
    1148          35 :             return nullptr;
    1149             :         }
    1150             : 
    1151         125 :         bUseStatementForGetNextFeature = false;
    1152         125 :         bEmptyLayer = true;
    1153             :     }
    1154             : 
    1155             :     /* -------------------------------------------------------------------- */
    1156             :     /*      Create layer.                                                   */
    1157             :     /* -------------------------------------------------------------------- */
    1158             : 
    1159         595 :     auto poDrv = poDS->GetDriver();
    1160             :     const bool bCanReopenBaseDS =
    1161         595 :         !(poDrv && EQUAL(poDrv->GetDescription(), "Memory"));
    1162             :     OGRSQLiteSelectLayer *poLayer = new OGRSQLiteExecuteSQLLayer(
    1163             :         pszTmpDBName, poSQLiteDS, pszStatement, hSQLStmt,
    1164             :         bUseStatementForGetNextFeature, bEmptyLayer, bCanReopenBaseDS,
    1165         595 :         bStringsAsUTF8);
    1166             : 
    1167         595 :     if (poSpatialFilter != nullptr)
    1168             :     {
    1169           6 :         const auto nErrorCounter = CPLGetErrorCounter();
    1170           6 :         poLayer->SetSpatialFilter(0, poSpatialFilter);
    1171           8 :         if (CPLGetErrorCounter() > nErrorCounter &&
    1172           2 :             CPLGetLastErrorType() != CE_None)
    1173             :         {
    1174           2 :             delete poLayer;
    1175           2 :             return nullptr;
    1176             :         }
    1177             :     }
    1178             : 
    1179         593 :     if (poSingleSrcLayer != nullptr)
    1180         316 :         poLayer->SetMetadata(poSingleSrcLayer->GetMetadata("NATIVE_DATA"),
    1181         316 :                              "NATIVE_DATA");
    1182             : 
    1183         593 :     return poLayer;
    1184             : }
    1185             : 
    1186             : #endif  // HAVE_SQLITE3EXT_H

Generated by: LCOV version 1.14