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

Generated by: LCOV version 1.14