LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/sqlite - ogrsqlitedatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 452 314 69.5 %
Date: 2010-01-09 Functions: 20 18 90.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrsqlitedatasource.cpp 17990 2009-11-11 12:06:49Z chaitanya $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGRSQLiteDataSource class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogr_sqlite.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_string.h"
      33                 : #include "cpl_hash_set.h"
      34                 : 
      35                 : #ifdef HAVE_SPATIALITE
      36                 : #include "spatialite.h"
      37                 : #endif
      38                 : 
      39                 : static int bSpatialiteLoaded = FALSE;
      40                 : 
      41                 : CPL_CVSID("$Id: ogrsqlitedatasource.cpp 17990 2009-11-11 12:06:49Z chaitanya $");
      42                 : 
      43                 : /************************************************************************/
      44                 : /*                        OGRSQLiteDataSource()                         */
      45                 : /************************************************************************/
      46                 : 
      47              32 : OGRSQLiteDataSource::OGRSQLiteDataSource()
      48                 : 
      49                 : {
      50              32 :     pszName = NULL;
      51              32 :     papoLayers = NULL;
      52              32 :     nLayers = 0;
      53                 : 
      54              32 :     nSoftTransactionLevel = 0;
      55                 : 
      56              32 :     nKnownSRID = 0;
      57              32 :     panSRID = NULL;
      58              32 :     papoSRS = NULL;
      59                 : 
      60              32 :     bHaveGeometryColumns = FALSE;
      61              32 :     bIsSpatiaLite = FALSE;
      62              32 : }
      63                 : 
      64                 : /************************************************************************/
      65                 : /*                        ~OGRSQLiteDataSource()                        */
      66                 : /************************************************************************/
      67                 : 
      68              64 : OGRSQLiteDataSource::~OGRSQLiteDataSource()
      69                 : 
      70                 : {
      71                 :     int         i;
      72                 : 
      73              32 :     CPLFree( pszName );
      74                 : 
      75             136 :     for( i = 0; i < nLayers; i++ )
      76             104 :         delete papoLayers[i];
      77                 :     
      78              32 :     CPLFree( papoLayers );
      79                 : 
      80              44 :     for( i = 0; i < nKnownSRID; i++ )
      81                 :     {
      82              12 :         if( papoSRS[i] != NULL )
      83              12 :             papoSRS[i]->Release();
      84                 :     }
      85              32 :     CPLFree( panSRID );
      86              32 :     CPLFree( papoSRS );
      87                 : 
      88              32 :     if( hDB != NULL )
      89              32 :         sqlite3_close( hDB );
      90              64 : }
      91                 : 
      92                 : /************************************************************************/
      93                 : /*                     SpatiaLiteToOGRGeomType()                        */
      94                 : /*      Map SpatiaLite geometry format strings to corresponding         */
      95                 : /*      OGR constants.                                                  */
      96                 : /************************************************************************/
      97                 : 
      98                 : OGRwkbGeometryType
      99               6 : OGRSQLiteDataSource::SpatiaLiteToOGRGeomType( const char *pszGeomType )
     100                 : {
     101               6 :     if ( EQUAL(pszGeomType, "POINT") )
     102               0 :         return wkbPoint;
     103               6 :     else if ( EQUAL(pszGeomType, "LINESTRING") )
     104               0 :         return wkbLineString;
     105               6 :     else if ( EQUAL(pszGeomType, "POLYGON") )
     106               4 :         return wkbPolygon;
     107               2 :     else if ( EQUAL(pszGeomType, "MULTIPOINT") )
     108               0 :         return wkbMultiPoint;
     109               2 :     else if ( EQUAL(pszGeomType, "MULTILINESTRING") )
     110               0 :         return wkbMultiLineString;
     111               2 :     else if ( EQUAL(pszGeomType, "MULTIPOLYGON") )
     112               0 :         return wkbMultiPolygon;
     113               2 :     else if ( EQUAL(pszGeomType, "GEOMETRYCOLLECTION") )
     114               0 :         return wkbGeometryCollection;
     115                 :     else
     116               2 :         return wkbUnknown;
     117                 : }
     118                 : 
     119                 : /************************************************************************/
     120                 : /*                     OGRToSpatiaLiteGeomType()                        */
     121                 : /*      Map OGR geometry format constants to corresponding              */
     122                 : /*      SpatiaLite strings                                              */
     123                 : /************************************************************************/
     124                 : 
     125                 : const char *
     126               1 : OGRSQLiteDataSource::OGRToSpatiaLiteGeomType( OGRwkbGeometryType eGeomType )
     127                 : {
     128               1 :     switch ( wkbFlatten(eGeomType) )
     129                 :     {
     130                 :         case wkbUnknown:
     131               1 :             return "GEOMETRY";
     132                 :         case wkbPoint:
     133               0 :             return "POINT";
     134                 :         case wkbLineString:
     135               0 :             return "LINESTRING";
     136                 :         case wkbPolygon:
     137               0 :             return "POLYGON";
     138                 :         case wkbMultiPoint:
     139               0 :             return "MULTIPOINT";
     140                 :         case wkbMultiLineString:
     141               0 :             return "MULTILINESTRING";
     142                 :         case wkbMultiPolygon:
     143               0 :             return "MULTIPOLYGON";
     144                 :         case wkbGeometryCollection:
     145               0 :             return "GEOMETRYCOLLECTION";
     146                 :         default:
     147               0 :             return "";
     148                 :     }
     149                 : }
     150                 : 
     151                 : /************************************************************************/
     152                 : /*                                Open()                                */
     153                 : /*                                                                      */
     154                 : /*      Note, the Open() will implicitly create the database if it      */
     155                 : /*      does not already exist.                                         */
     156                 : /************************************************************************/
     157                 : 
     158              32 : int OGRSQLiteDataSource::Open( const char * pszNewName )
     159                 : 
     160                 : {
     161                 :     CPLAssert( nLayers == 0 );
     162                 : 
     163              32 :     pszName = CPLStrdup( pszNewName );
     164                 : 
     165                 : /* -------------------------------------------------------------------- */
     166                 : /*      Try loading SpatiaLite.                                         */
     167                 : /* -------------------------------------------------------------------- */
     168                 : #ifdef HAVE_SPATIALITE
     169                 :     if (!bSpatialiteLoaded && CSLTestBoolean(CPLGetConfigOption("SPATIALITE_LOAD", "TRUE")))
     170                 :     {
     171                 :         bSpatialiteLoaded = TRUE;
     172                 :         spatialite_init(CSLTestBoolean(CPLGetConfigOption("SPATIALITE_INIT_VERBOSE", "FALSE")));
     173                 :     }
     174                 : #endif
     175                 : 
     176              32 :     int bListAllTables = CSLTestBoolean(CPLGetConfigOption("SQLITE_LIST_ALL_TABLES", "NO"));
     177                 : 
     178                 : /* -------------------------------------------------------------------- */
     179                 : /*      Try to open the sqlite database properly now.                   */
     180                 : /* -------------------------------------------------------------------- */
     181                 :     int rc;
     182                 : 
     183              32 :     hDB = NULL;
     184              32 :     rc = sqlite3_open( pszNewName, &hDB );
     185              32 :     if( rc != SQLITE_OK )
     186                 :     {
     187                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     188                 :                   "sqlite3_open(%s) failed: %s", 
     189               0 :                   pszNewName, sqlite3_errmsg( hDB ) );
     190                 :                   
     191               0 :         return FALSE;
     192                 :     }
     193                 :     
     194              32 :     CPLHashSet* hSet = CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, CPLFree);
     195                 : 
     196                 : /* -------------------------------------------------------------------- */
     197                 : /*      If we have a GEOMETRY_COLUMNS tables, initialize on the basis   */
     198                 : /*      of that.                                                        */
     199                 : /* -------------------------------------------------------------------- */
     200                 :     char **papszResult;
     201                 :     int nRowCount, iRow, nColCount;
     202                 :     char *pszErrMsg;
     203                 : 
     204                 :     rc = sqlite3_get_table( 
     205                 :         hDB,
     206                 :         "SELECT f_table_name, f_geometry_column, geometry_type, coord_dimension, geometry_format, srid"
     207                 :         " FROM geometry_columns",
     208              32 :         &papszResult, &nRowCount, &nColCount, &pszErrMsg );
     209                 : 
     210              32 :     if( rc == SQLITE_OK )
     211                 :     {
     212               9 :         CPLDebug("SQLITE", "OGR style SQLite DB found !");
     213                 :     
     214               9 :         bHaveGeometryColumns = TRUE;
     215                 : 
     216              40 :         for( iRow = 0; iRow < nRowCount; iRow++ )
     217                 :         {
     218              31 :             char **papszRow = papszResult + iRow * 6 + 6;
     219              31 :             OGRwkbGeometryType eGeomType = wkbUnknown;
     220              31 :             int nSRID = 0;
     221                 : 
     222              31 :             eGeomType = (OGRwkbGeometryType) atoi(papszRow[2]);
     223                 : 
     224              31 :             if( atoi(papszRow[3]) > 2 )
     225               0 :                 eGeomType = (OGRwkbGeometryType) (((int)eGeomType) | wkb25DBit);
     226                 : 
     227              31 :             if( papszRow[5] != NULL )
     228               7 :                 nSRID = atoi(papszRow[5]);
     229                 : 
     230              62 :             OpenTable( papszRow[0], papszRow[1], eGeomType, papszRow[4],
     231              93 :                        FetchSRS( nSRID ) );
     232                 :                        
     233              31 :             if (bListAllTables)
     234               0 :                 CPLHashSetInsert(hSet, CPLStrdup(papszRow[0]));
     235                 :         }
     236                 : 
     237               9 :         sqlite3_free_table(papszResult);
     238                 : 
     239               9 :         if (bListAllTables)
     240               0 :             goto all_tables;
     241                 :             
     242               9 :         CPLHashSetDestroy(hSet);
     243                 :         
     244               9 :         return TRUE;
     245                 :     }
     246                 : 
     247                 : /* -------------------------------------------------------------------- */
     248                 : /*      Otherwise we can deal with SpatiaLite database.                 */
     249                 : /* -------------------------------------------------------------------- */
     250              23 :     sqlite3_free( pszErrMsg );
     251                 :     rc = sqlite3_get_table( hDB,
     252                 :                             "SELECT f_table_name, f_geometry_column, "
     253                 :                             "type, coord_dimension, srid, "
     254                 :                             "spatial_index_enabled FROM geometry_columns",
     255                 :                             &papszResult, &nRowCount, 
     256              23 :                             &nColCount, &pszErrMsg );
     257                 : 
     258              23 :     if ( rc == SQLITE_OK )
     259                 :     {
     260              23 :         CPLDebug("SQLITE", "SpatiaLite-style SQLite DB found !");
     261                 :         
     262              23 :         bIsSpatiaLite = TRUE;
     263              23 :         bHaveGeometryColumns = TRUE;
     264                 : 
     265              29 :         for ( iRow = 0; iRow < nRowCount; iRow++ )
     266                 :         {
     267               6 :             char **papszRow = papszResult + iRow * 6 + 6;
     268                 :             OGRwkbGeometryType eGeomType;
     269               6 :             int nSRID = 0;
     270               6 :             int bHasSpatialIndex = FALSE;
     271                 : 
     272               6 :             eGeomType = SpatiaLiteToOGRGeomType(papszRow[2]);
     273                 : 
     274               6 :             if( atoi(papszRow[3]) > 2 )
     275               0 :                 eGeomType = (OGRwkbGeometryType) (((int)eGeomType) | wkb25DBit);
     276                 : 
     277               6 :             if( papszRow[4] != NULL )
     278               6 :                 nSRID = atoi(papszRow[4]);
     279                 : 
     280                 :             /* Only look for presence of a spatial index if linked against SpatiaLite */
     281               6 :             if( bSpatialiteLoaded && papszRow[5] != NULL )
     282               0 :                 bHasSpatialIndex = atoi(papszRow[5]);
     283                 : 
     284               6 :             OpenTable( papszRow[0], papszRow[1], eGeomType, "SpatiaLite",
     285              12 :                        FetchSRS( nSRID ), nSRID, bHasSpatialIndex );
     286                 :                        
     287               6 :             if (bListAllTables)
     288               4 :                 CPLHashSetInsert(hSet, CPLStrdup(papszRow[0]));
     289                 :         }
     290                 : 
     291              23 :         sqlite3_free_table(papszResult);
     292                 : 
     293                 : /* -------------------------------------------------------------------- */
     294                 : /*      Detect VirtualShape layers                                      */
     295                 : /* -------------------------------------------------------------------- */
     296                 : #ifdef HAVE_SPATIALITE
     297                 :         if (bSpatialiteLoaded)
     298                 :         {
     299                 :             rc = sqlite3_get_table( hDB,
     300                 :                                 "SELECT name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE % USING %VirtualShape%'",
     301                 :                                 &papszResult, &nRowCount, 
     302                 :                                 &nColCount, &pszErrMsg );
     303                 : 
     304                 :             if ( rc == SQLITE_OK )
     305                 :             {
     306                 :                 for( iRow = 0; iRow < nRowCount; iRow++ )
     307                 :                 {
     308                 :                     OpenTable( papszResult[iRow+1] );
     309                 :                     
     310                 :                     if (bListAllTables)
     311                 :                         CPLHashSetInsert(hSet, CPLStrdup(papszResult[iRow+1]));
     312                 :                 }
     313                 :             }
     314                 :             else
     315                 :             {
     316                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
     317                 :                         "Unable to fetch list of tables: %s", 
     318                 :                         pszErrMsg );
     319                 :                 sqlite3_free( pszErrMsg );
     320                 :             }
     321                 : 
     322                 :             sqlite3_free_table(papszResult);
     323                 :         }
     324                 : #endif
     325                 : 
     326              23 :         if (bListAllTables)
     327              19 :             goto all_tables;
     328                 : 
     329               4 :         CPLHashSetDestroy(hSet);
     330                 :         
     331               4 :         return TRUE;
     332                 :     }
     333                 : 
     334                 : /* -------------------------------------------------------------------- */
     335                 : /*      Otherwise our final resort is to return all tables and views    */
     336                 : /*      as non-spatial tables.                                          */
     337                 : /* -------------------------------------------------------------------- */
     338               0 :     sqlite3_free( pszErrMsg );
     339                 :     
     340                 : all_tables:
     341                 :     rc = sqlite3_get_table( hDB,
     342                 :                             "SELECT name FROM sqlite_master "
     343                 :                             "WHERE type IN ('table','view') "
     344                 :                             "UNION ALL "
     345                 :                             "SELECT name FROM sqlite_temp_master "
     346                 :                             "WHERE type IN ('table','view') "
     347                 :                             "ORDER BY 1",
     348                 :                             &papszResult, &nRowCount, 
     349              19 :                             &nColCount, &pszErrMsg );
     350                 : 
     351              19 :     if( rc != SQLITE_OK )
     352                 :     {
     353                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     354                 :                   "Unable to fetch list of tables: %s", 
     355               0 :                   pszErrMsg );
     356               0 :         sqlite3_free( pszErrMsg );
     357               0 :         CPLHashSetDestroy(hSet);
     358               0 :         return FALSE;
     359                 :     }
     360                 :     
     361              90 :     for( iRow = 0; iRow < nRowCount; iRow++ )
     362                 :     {
     363              71 :         if (CPLHashSetLookup(hSet, papszResult[iRow+1]) == NULL)
     364              67 :             OpenTable( papszResult[iRow+1] );
     365                 :     }
     366                 :     
     367              19 :     sqlite3_free_table(papszResult);
     368              19 :     CPLHashSetDestroy(hSet);
     369                 : 
     370              19 :     return TRUE;
     371                 : }
     372                 : 
     373                 : /************************************************************************/
     374                 : /*                             OpenTable()                              */
     375                 : /************************************************************************/
     376                 : 
     377             104 : int OGRSQLiteDataSource::OpenTable( const char *pszNewName, 
     378                 :                                     const char *pszGeomCol,
     379                 :                                     OGRwkbGeometryType eGeomType,
     380                 :                                     const char *pszGeomFormat,
     381                 :                                     OGRSpatialReference *poSRS, int nSRID,
     382                 :                                     int bHasSpatialIndex)
     383                 : 
     384                 : {
     385                 : /* -------------------------------------------------------------------- */
     386                 : /*      Create the layer object.                                        */
     387                 : /* -------------------------------------------------------------------- */
     388                 :     OGRSQLiteTableLayer  *poLayer;
     389                 : 
     390             104 :     poLayer = new OGRSQLiteTableLayer( this );
     391                 : 
     392             104 :     if( poLayer->Initialize( pszNewName, pszGeomCol, 
     393                 :                              eGeomType, pszGeomFormat,
     394                 :                              poSRS, nSRID, bHasSpatialIndex ) )
     395                 :     {
     396               0 :         delete poLayer;
     397               0 :         return FALSE;
     398                 :     }
     399                 : 
     400                 : /* -------------------------------------------------------------------- */
     401                 : /*      Add layer to data source layer list.                            */
     402                 : /* -------------------------------------------------------------------- */
     403                 :     papoLayers = (OGRSQLiteLayer **)
     404             104 :         CPLRealloc( papoLayers,  sizeof(OGRSQLiteLayer *) * (nLayers+1) );
     405             104 :     papoLayers[nLayers++] = poLayer;
     406                 :     
     407             104 :     return TRUE;
     408                 : }
     409                 : 
     410                 : /************************************************************************/
     411                 : /*                           TestCapability()                           */
     412                 : /************************************************************************/
     413                 : 
     414               0 : int OGRSQLiteDataSource::TestCapability( const char * pszCap )
     415                 : 
     416                 : {
     417               0 :     if( EQUAL(pszCap,ODsCCreateLayer) )
     418               0 :         return TRUE;
     419                 :     else
     420               0 :         return FALSE;
     421                 : }
     422                 : 
     423                 : /************************************************************************/
     424                 : /*                              GetLayer()                              */
     425                 : /************************************************************************/
     426                 : 
     427             238 : OGRLayer *OGRSQLiteDataSource::GetLayer( int iLayer )
     428                 : 
     429                 : {
     430             238 :     if( iLayer < 0 || iLayer >= nLayers )
     431               0 :         return NULL;
     432                 :     else
     433             238 :         return papoLayers[iLayer];
     434                 : }
     435                 : 
     436                 : /************************************************************************/
     437                 : /*                             ExecuteSQL()                             */
     438                 : /************************************************************************/
     439                 : 
     440             118 : OGRLayer * OGRSQLiteDataSource::ExecuteSQL( const char *pszSQLCommand,
     441                 :                                           OGRGeometry *poSpatialFilter,
     442                 :                                           const char *pszDialect )
     443                 : 
     444                 : {
     445             118 :     if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
     446                 :         return OGRDataSource::ExecuteSQL( pszSQLCommand, 
     447                 :                                           poSpatialFilter, 
     448               0 :                                           pszDialect );
     449                 : 
     450                 : /* -------------------------------------------------------------------- */
     451                 : /*      Special case DELLAYER: command.                                 */
     452                 : /* -------------------------------------------------------------------- */
     453             118 :     if( EQUALN(pszSQLCommand,"DELLAYER:",9) )
     454                 :     {
     455               9 :         const char *pszLayerName = pszSQLCommand + 9;
     456                 : 
     457              18 :         while( *pszLayerName == ' ' )
     458               0 :             pszLayerName++;
     459                 : 
     460               9 :         DeleteLayer( pszLayerName );
     461               9 :         return NULL;
     462                 :     }
     463                 : 
     464                 : /* -------------------------------------------------------------------- */
     465                 : /*      Prepare statement.                                              */
     466                 : /* -------------------------------------------------------------------- */
     467                 :     int rc;
     468             109 :     sqlite3_stmt *hSQLStmt = NULL;
     469                 : 
     470                 :     rc = sqlite3_prepare( GetDB(), pszSQLCommand, strlen(pszSQLCommand),
     471             109 :                           &hSQLStmt, NULL );
     472                 : 
     473             109 :     if( rc != SQLITE_OK )
     474                 :     {
     475                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     476                 :                 "In ExecuteSQL(): sqlite3_prepare(%s):\n  %s", 
     477              17 :                 pszSQLCommand, sqlite3_errmsg(GetDB()) );
     478                 : 
     479              17 :         if( hSQLStmt != NULL )
     480                 :         {
     481               0 :             sqlite3_finalize( hSQLStmt );
     482                 :         }
     483                 : 
     484              17 :         return NULL;
     485                 :     }
     486                 : 
     487                 : /* -------------------------------------------------------------------- */
     488                 : /*      Do we get a resultset?                                          */
     489                 : /* -------------------------------------------------------------------- */
     490              92 :     rc = sqlite3_step( hSQLStmt );
     491              92 :     if( rc != SQLITE_ROW )
     492                 :     {
     493              72 :         if ( rc != SQLITE_DONE )
     494                 :         {
     495                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     496                 :                   "In ExecuteSQL(): sqlite3_step(%s):\n  %s", 
     497               0 :                   pszSQLCommand, sqlite3_errmsg(GetDB()) );
     498                 :         }
     499              72 :         sqlite3_finalize( hSQLStmt );
     500              72 :         return NULL;
     501                 :     }
     502                 :     
     503                 : /* -------------------------------------------------------------------- */
     504                 : /*      Create layer.                                                   */
     505                 : /* -------------------------------------------------------------------- */
     506              20 :     OGRSQLiteSelectLayer *poLayer = NULL;
     507                 :         
     508              20 :     poLayer = new OGRSQLiteSelectLayer( this, hSQLStmt );
     509                 : 
     510              20 :     if( poSpatialFilter != NULL )
     511               0 :         poLayer->SetSpatialFilter( poSpatialFilter );
     512                 :     
     513              20 :     return poLayer;
     514                 : }
     515                 : 
     516                 : /************************************************************************/
     517                 : /*                          ReleaseResultSet()                          */
     518                 : /************************************************************************/
     519                 : 
     520              20 : void OGRSQLiteDataSource::ReleaseResultSet( OGRLayer * poLayer )
     521                 : 
     522                 : {
     523              20 :     delete poLayer;
     524              20 : }
     525                 : 
     526                 : /************************************************************************/
     527                 : /*                            CreateLayer()                             */
     528                 : /************************************************************************/
     529                 : 
     530                 : OGRLayer *
     531               8 : OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
     532                 :                                   OGRSpatialReference *poSRS,
     533                 :                                   OGRwkbGeometryType eType,
     534                 :                                   char ** papszOptions )
     535                 : 
     536                 : {
     537                 :     char                *pszLayerName;
     538                 :     const char          *pszGeomFormat;
     539                 : 
     540               8 :     if( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) )
     541               8 :         pszLayerName = LaunderName( pszLayerNameIn );
     542                 :     else
     543               0 :         pszLayerName = CPLStrdup( pszLayerNameIn );
     544                 :     
     545               8 :     pszGeomFormat = CSLFetchNameValue( papszOptions, "FORMAT" );
     546               8 :     if( pszGeomFormat == NULL )
     547                 :     {
     548               5 :         if ( !bIsSpatiaLite )
     549               4 :             pszGeomFormat = "WKB";
     550                 :         else
     551               1 :             pszGeomFormat = "SpatiaLite";
     552                 :     }
     553                 : 
     554               8 :     if( !EQUAL(pszGeomFormat,"WKT") 
     555                 :         && !EQUAL(pszGeomFormat,"WKB")
     556                 :         && !EQUAL(pszGeomFormat, "SpatiaLite") )
     557                 :     {
     558                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     559                 :                   "FORMAT=%s not recognised or supported.", 
     560               0 :                   pszGeomFormat );
     561               0 :         return NULL;
     562                 :     }
     563                 : 
     564                 : /* -------------------------------------------------------------------- */
     565                 : /*      Do we already have this layer?  If so, should we blow it        */
     566                 : /*      away?                                                           */
     567                 : /* -------------------------------------------------------------------- */
     568                 :     int iLayer;
     569                 : 
     570              29 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
     571                 :     {
     572              21 :         if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
     573                 :         {
     574               0 :             if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
     575                 :                 && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
     576                 :             {
     577               0 :                 DeleteLayer( pszLayerName );
     578                 :             }
     579                 :             else
     580                 :             {
     581                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
     582                 :                           "Layer %s already exists, CreateLayer failed.\n"
     583                 :                           "Use the layer creation option OVERWRITE=YES to "
     584                 :                           "replace it.",
     585               0 :                           pszLayerName );
     586               0 :                 CPLFree( pszLayerName );
     587               0 :                 return NULL;
     588                 :             }
     589                 :         }
     590                 :     }
     591                 : 
     592                 : /* -------------------------------------------------------------------- */
     593                 : /*      Try to get the SRS Id of this spatial reference system,         */
     594                 : /*      adding to the srs table if needed.                              */
     595                 : /* -------------------------------------------------------------------- */
     596               8 :     int nSRSId = -1;
     597                 : 
     598               8 :     if( poSRS != NULL )
     599               3 :         nSRSId = FetchSRSId( poSRS );
     600                 : 
     601                 : /* -------------------------------------------------------------------- */
     602                 : /*      Create a basic table with the FID.  Also include the            */
     603                 : /*      geometry if this is not a PostGIS enabled table.                */
     604                 : /* -------------------------------------------------------------------- */
     605                 :     int rc;
     606                 :     char *pszErrMsg;
     607               8 :     const char *pszGeomCol = NULL;
     608               8 :     CPLString osCommand;
     609                 : 
     610               8 :     if( eType == wkbNone )
     611                 :         osCommand.Printf( 
     612                 :             "CREATE TABLE '%s' ( OGC_FID INTEGER PRIMARY KEY )", 
     613               0 :             pszLayerName );
     614                 :     else
     615                 :     {
     616               8 :         if( EQUAL(pszGeomFormat,"WKT") )
     617                 :         {
     618               1 :             pszGeomCol = "WKT_GEOMETRY";
     619                 :             osCommand.Printf(
     620                 :                 "CREATE TABLE '%s' ( "
     621                 :                 "  OGC_FID INTEGER PRIMARY KEY,"
     622                 :                 "  %s VARCHAR )", 
     623               1 :                 pszLayerName, pszGeomCol );
     624                 :         }
     625                 :         else
     626                 :         {
     627               7 :             pszGeomCol = "GEOMETRY";
     628                 :             osCommand.Printf(
     629                 :                 "CREATE TABLE '%s' ( "
     630                 :                 "  OGC_FID INTEGER PRIMARY KEY,"
     631                 :                 "  %s BLOB )", 
     632               7 :                 pszLayerName, pszGeomCol );
     633                 :         }
     634                 :     }
     635                 : 
     636                 : #ifdef DEBUG
     637                 :     CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
     638                 : #endif
     639                 : 
     640               8 :     rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
     641               8 :     if( rc != SQLITE_OK )
     642                 :     {
     643                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     644                 :                   "Unable to create table %s: %s",
     645               0 :                   pszLayerName, pszErrMsg );
     646               0 :         sqlite3_free( pszErrMsg );
     647               0 :         return FALSE;
     648                 :     }
     649                 : 
     650                 : /* -------------------------------------------------------------------- */
     651                 : /*      Eventually we should be adding this table to a table of         */
     652                 : /*      "geometric layers", capturing the WKT projection, and           */
     653                 : /*      perhaps some other housekeeping.                                */
     654                 : /* -------------------------------------------------------------------- */
     655               8 :     if( bHaveGeometryColumns && eType != wkbNone )
     656                 :     {
     657                 :         int nCoordDim;
     658                 : 
     659                 :         /* Sometimes there is an old cruft entry in the geometry_columns
     660                 :          * table if things were not properly cleaned up before.  We make
     661                 :          * an effort to clean out such cruft.
     662                 :          */
     663                 :         osCommand.Printf(
     664                 :             "DELETE FROM geometry_columns WHERE f_table_name = '%s'", 
     665               8 :             pszLayerName );
     666                 :                  
     667                 : #ifdef DEBUG
     668                 :         CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
     669                 : #endif
     670                 : 
     671               8 :         rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
     672               8 :         if( rc != SQLITE_OK )
     673                 :         {
     674               0 :             sqlite3_free( pszErrMsg );
     675               0 :             return FALSE;
     676                 :         }
     677                 :         
     678               8 :         if( eType == wkbFlatten(eType) )
     679               8 :             nCoordDim = 2;
     680                 :         else
     681               0 :             nCoordDim = 3;
     682                 : 
     683               8 :         if( nSRSId > 0 )
     684                 :         {
     685               3 :             if ( bIsSpatiaLite )
     686                 :                 osCommand.Printf(
     687                 :                     "INSERT INTO geometry_columns "
     688                 :                     "(f_table_name, f_geometry_column, type, "
     689                 :                     "coord_dimension, srid, spatial_index_enabled) "
     690                 :                     "VALUES ('%s','%s', '%s', %d, %d, 0)", 
     691                 :                     pszLayerName, pszGeomCol, OGRToSpatiaLiteGeomType(eType),
     692               1 :                     nCoordDim, nSRSId );
     693                 :             else
     694                 :                 osCommand.Printf(
     695                 :                     "INSERT INTO geometry_columns "
     696                 :                     "(f_table_name, f_geometry_column, geometry_format, "
     697                 :                     "geometry_type, coord_dimension, srid) VALUES "
     698                 :                     "('%s','%s','%s', %d, %d, %d)", 
     699                 :                     pszLayerName, pszGeomCol, pszGeomFormat,
     700               2 :                     (int) wkbFlatten(eType), nCoordDim, nSRSId );
     701                 :         }
     702                 :         else
     703                 :         {
     704               5 :             if ( bIsSpatiaLite )
     705                 :                 osCommand.Printf(
     706                 :                     "INSERT INTO geometry_columns "
     707                 :                     "(f_table_name, f_geometry_column, type, "
     708                 :                     "coord_dimension, spatial_index_enabled) "
     709                 :                     "VALUES ('%s','%s', '%s', %d, 0)", 
     710                 :                     pszLayerName, pszGeomCol, OGRToSpatiaLiteGeomType(eType),
     711               0 :                     nCoordDim );
     712                 :             else
     713                 :                 osCommand.Printf(
     714                 :                     "INSERT INTO geometry_columns "
     715                 :                     "(f_table_name, f_geometry_column, geometry_format, "
     716                 :                     "geometry_type, coord_dimension) VALUES "
     717                 :                     "('%s','%s','%s', %d, %d)", 
     718                 :                     pszLayerName, pszGeomCol, pszGeomFormat,
     719               5 :                     (int) wkbFlatten(eType), nCoordDim );
     720                 :         }
     721                 : 
     722                 : #ifdef DEBUG
     723                 :         CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
     724                 : #endif
     725                 : 
     726               8 :         rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
     727               8 :         if( rc != SQLITE_OK )
     728                 :         {
     729                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     730                 :                       "Unable to add %s table to geometry_columns:\n%s",
     731               0 :                       pszLayerName, pszErrMsg );
     732               0 :             sqlite3_free( pszErrMsg );
     733               0 :             return FALSE;
     734                 :         }
     735                 : 
     736                 : /* -------------------------------------------------------------------- */
     737                 : /*      Create the spatial index.                                       */
     738                 : /*                                                                      */
     739                 : /*      We're doing this before we add geometry and record to the table */
     740                 : /*      so this may not be exactly the best way to do it.               */
     741                 : /* -------------------------------------------------------------------- */
     742                 : #ifdef HAVE_SPATIALITE
     743                 :         /* Only if linked against SpatiaLite and the datasource was created as a SpatiaLite DB */
     744                 :         if ( bIsSpatiaLite && bSpatialiteLoaded )
     745                 : #else
     746               8 :         if ( 0 )
     747                 : #endif
     748                 :         {
     749                 :             const char* pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
     750                 :             if( pszSI == NULL || CSLTestBoolean(pszSI) )
     751                 :             {
     752                 :                 osCommand.Printf("SELECT CreateSpatialIndex('%s', '%s')",
     753                 :                                  pszLayerName, pszGeomCol);
     754                 : 
     755                 :             /* -------------------------------------------------------------------- */
     756                 :             /*      Prepare statement.                                              */
     757                 :             /* -------------------------------------------------------------------- */
     758                 :                 int rc;
     759                 :                 sqlite3_stmt *hSQLStmt = NULL;
     760                 : 
     761                 :                 rc = sqlite3_prepare( GetDB(), osCommand, strlen(osCommand),
     762                 :                                       &hSQLStmt, NULL );
     763                 : 
     764                 :                 if( rc != SQLITE_OK )
     765                 :                 {
     766                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
     767                 :                             "In CreateLayer(): sqlite3_prepare(%s):\n  %s", 
     768                 :                             osCommand.c_str(), sqlite3_errmsg(GetDB()) );
     769                 :                 }
     770                 :                 else
     771                 :                 {
     772                 :                     /* -------------------------------------------------------------------- */
     773                 :                     /*      Do we get a resultset?                                          */
     774                 :                     /* -------------------------------------------------------------------- */
     775                 :                     rc = sqlite3_step( hSQLStmt );
     776                 :                     if( rc != SQLITE_ROW )
     777                 :                     {
     778                 :                         if ( rc != SQLITE_DONE )
     779                 :                         {
     780                 :                             CPLError( CE_Failure, CPLE_AppDefined, 
     781                 :                                 "In CreateLayer(): sqlite3_step(%s):\n  %s", 
     782                 :                                 osCommand.c_str(), sqlite3_errmsg(GetDB()) );
     783                 :                         }
     784                 :                     }
     785                 :                     else
     786                 :                     {
     787                 :                         if (sqlite3_column_count(hSQLStmt) != 1 &&
     788                 :                             sqlite3_column_int(hSQLStmt, 0) != 1)
     789                 :                         {
     790                 :                             CPLError( CE_Failure, CPLE_AppDefined, 
     791                 :                                 "In CreateLayer(): sqlite3_step(%s): did not get expected result", 
     792                 :                                 osCommand.c_str() );
     793                 :                         }
     794                 :                     }
     795                 :                 }
     796                 : 
     797                 :                 if( hSQLStmt != NULL )
     798                 :                 {
     799                 :                     sqlite3_finalize( hSQLStmt );
     800                 :                 }
     801                 :             }
     802                 :         }
     803                 :     }
     804                 : 
     805                 : /* -------------------------------------------------------------------- */
     806                 : /*      Create the layer object.                                        */
     807                 : /* -------------------------------------------------------------------- */
     808                 :     OGRSQLiteTableLayer     *poLayer;
     809                 : 
     810               8 :     poLayer = new OGRSQLiteTableLayer( this );
     811                 : 
     812                 :     poLayer->Initialize( pszLayerName, pszGeomCol, eType, pszGeomFormat, 
     813              16 :                          FetchSRS(nSRSId), nSRSId );
     814                 : 
     815               8 :     poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
     816                 : 
     817                 : /* -------------------------------------------------------------------- */
     818                 : /*      Add layer to data source layer list.                            */
     819                 : /* -------------------------------------------------------------------- */
     820                 :     papoLayers = (OGRSQLiteLayer **)
     821               8 :         CPLRealloc( papoLayers,  sizeof(OGRSQLiteLayer *) * (nLayers+1) );
     822                 :     
     823               8 :     papoLayers[nLayers++] = poLayer;
     824                 : 
     825               8 :     CPLFree( pszLayerName );
     826                 : 
     827               8 :     return poLayer;
     828                 : }
     829                 : 
     830                 : /************************************************************************/
     831                 : /*                            LaunderName()                             */
     832                 : /************************************************************************/
     833                 : 
     834              17 : char *OGRSQLiteDataSource::LaunderName( const char *pszSrcName )
     835                 : 
     836                 : {
     837              17 :     char    *pszSafeName = CPLStrdup( pszSrcName );
     838                 :     int     i;
     839                 : 
     840             154 :     for( i = 0; pszSafeName[i] != '\0'; i++ )
     841                 :     {
     842             137 :         pszSafeName[i] = (char) tolower( pszSafeName[i] );
     843             137 :         if( pszSafeName[i] == '-' || pszSafeName[i] == '#' )
     844               0 :             pszSafeName[i] = '_';
     845                 :     }
     846                 : 
     847              17 :     return pszSafeName;
     848                 : }
     849                 : 
     850                 : /************************************************************************/
     851                 : /*                            DeleteLayer()                             */
     852                 : /************************************************************************/
     853                 : 
     854               9 : void OGRSQLiteDataSource::DeleteLayer( const char *pszLayerName )
     855                 : 
     856                 : {
     857                 :     int iLayer;
     858                 : 
     859                 : /* -------------------------------------------------------------------- */
     860                 : /*      Try to find layer.                                              */
     861                 : /* -------------------------------------------------------------------- */
     862              12 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
     863                 :     {
     864              11 :         if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
     865               8 :             break;
     866                 :     }
     867                 : 
     868               9 :     if( iLayer == nLayers )
     869                 :     {
     870                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     871                 :                   "Attempt to delete layer '%s', but this layer is not known to OGR.", 
     872               1 :                   pszLayerName );
     873               1 :         return;
     874                 :     }
     875                 : 
     876                 : /* -------------------------------------------------------------------- */
     877                 : /*      Blow away our OGR structures related to the layer.  This is     */
     878                 : /*      pretty dangerous if anything has a reference to this layer!     */
     879                 : /* -------------------------------------------------------------------- */
     880               8 :     CPLDebug( "OGR_SQLITE", "DeleteLayer(%s)", pszLayerName );
     881                 : 
     882               8 :     delete papoLayers[iLayer];
     883                 :     memmove( papoLayers + iLayer, papoLayers + iLayer + 1, 
     884               8 :              sizeof(void *) * (nLayers - iLayer - 1) );
     885               8 :     nLayers--;
     886                 : 
     887                 : /* -------------------------------------------------------------------- */
     888                 : /*      Remove from the database.                                       */
     889                 : /* -------------------------------------------------------------------- */
     890                 :     int rc;
     891                 :     char *pszErrMsg;
     892                 : 
     893                 :     rc = sqlite3_exec( hDB, CPLSPrintf( "DROP TABLE '%s'", pszLayerName ),
     894               8 :                        NULL, NULL, &pszErrMsg );
     895               8 :     if( rc != SQLITE_OK )
     896                 :     {
     897                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     898                 :                   "Unable to drop table %s: %s",
     899               0 :                   pszLayerName, pszErrMsg );
     900               0 :         sqlite3_free( pszErrMsg );
     901               0 :         return;
     902                 :     }
     903                 : 
     904                 : /* -------------------------------------------------------------------- */
     905                 : /*      Drop from geometry_columns table.                               */
     906                 : /* -------------------------------------------------------------------- */
     907               8 :     if( bHaveGeometryColumns )
     908                 :     {
     909               8 :         CPLString osCommand;
     910                 : 
     911                 :         osCommand.Printf( 
     912                 :             "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
     913               8 :             pszLayerName );
     914                 :         
     915               8 :         rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
     916               8 :         if( rc != SQLITE_OK )
     917                 :         {
     918                 :             CPLError( CE_Warning, CPLE_AppDefined,
     919                 :                       "Removal from geometry_columns failed.\n%s: %s", 
     920               0 :                       osCommand.c_str(), pszErrMsg );
     921               0 :             sqlite3_free( pszErrMsg );
     922               8 :         }
     923                 :     }
     924                 : }
     925                 : 
     926                 : /************************************************************************/
     927                 : /*                        SoftStartTransaction()                        */
     928                 : /*                                                                      */
     929                 : /*      Create a transaction scope.  If we already have a               */
     930                 : /*      transaction active this isn't a real transaction, but just      */
     931                 : /*      an increment to the scope count.                                */
     932                 : /************************************************************************/
     933                 : 
     934              13 : OGRErr OGRSQLiteDataSource::SoftStartTransaction()
     935                 : 
     936                 : {
     937              13 :     nSoftTransactionLevel++;
     938                 : 
     939              13 :     if( nSoftTransactionLevel == 1 )
     940                 :     {
     941                 :         int rc;
     942                 :         char *pszErrMsg;
     943                 :         
     944                 : #ifdef DEBUG
     945                 :         CPLDebug( "OGR_SQLITE", "BEGIN Transaction" );
     946                 : #endif
     947                 : 
     948              13 :         rc = sqlite3_exec( hDB, "BEGIN", NULL, NULL, &pszErrMsg );
     949              13 :         if( rc != SQLITE_OK )
     950                 :         {
     951               0 :             nSoftTransactionLevel--;
     952                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     953                 :                       "BEGIN transaction failed: %s",
     954               0 :                       pszErrMsg );
     955               0 :             sqlite3_free( pszErrMsg );
     956               0 :             return OGRERR_FAILURE;
     957                 :         }
     958                 :     }
     959                 : 
     960              13 :     return OGRERR_NONE;
     961                 : }
     962                 : 
     963                 : /************************************************************************/
     964                 : /*                             SoftCommit()                             */
     965                 : /*                                                                      */
     966                 : /*      Commit the current transaction if we are at the outer           */
     967                 : /*      scope.                                                          */
     968                 : /************************************************************************/
     969                 : 
     970              12 : OGRErr OGRSQLiteDataSource::SoftCommit()
     971                 : 
     972                 : {
     973              12 :     if( nSoftTransactionLevel <= 0 )
     974                 :     {
     975               0 :         CPLDebug( "OGR_SQLITE", "SoftCommit() with no transaction active." );
     976               0 :         return OGRERR_FAILURE;
     977                 :     }
     978                 : 
     979              12 :     nSoftTransactionLevel--;
     980                 : 
     981              12 :     if( nSoftTransactionLevel == 0 )
     982                 :     {
     983                 :         int rc;
     984                 :         char *pszErrMsg;
     985                 :         
     986                 : #ifdef DEBUG
     987                 :         CPLDebug( "OGR_SQLITE", "COMMIT Transaction" );
     988                 : #endif
     989                 : 
     990              12 :         rc = sqlite3_exec( hDB, "COMMIT", NULL, NULL, &pszErrMsg );
     991              12 :         if( rc != SQLITE_OK )
     992                 :         {
     993                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     994                 :                       "COMMIT transaction failed: %s",
     995               0 :                       pszErrMsg );
     996               0 :             sqlite3_free( pszErrMsg );
     997               0 :             return OGRERR_FAILURE;
     998                 :         }
     999                 :     }
    1000                 : 
    1001              12 :     return OGRERR_NONE;
    1002                 : }
    1003                 : 
    1004                 : /************************************************************************/
    1005                 : /*                            SoftRollback()                            */
    1006                 : /*                                                                      */
    1007                 : /*      Force a rollback of the current transaction if there is one,    */
    1008                 : /*      even if we are nested several levels deep.                      */
    1009                 : /************************************************************************/
    1010                 : 
    1011               1 : OGRErr OGRSQLiteDataSource::SoftRollback()
    1012                 : 
    1013                 : {
    1014               1 :     if( nSoftTransactionLevel <= 0 )
    1015                 :     {
    1016               0 :         CPLDebug( "OGR_SQLITE", "SoftRollback() with no transaction active." );
    1017               0 :         return OGRERR_FAILURE;
    1018                 :     }
    1019                 : 
    1020               1 :     nSoftTransactionLevel = 0;
    1021                 : 
    1022                 :     int rc;
    1023                 :     char *pszErrMsg;
    1024                 :     
    1025                 : #ifdef DEBUG
    1026                 :     CPLDebug( "OGR_SQLITE", "ROLLBACK Transaction" );
    1027                 : #endif
    1028                 : 
    1029               1 :     rc = sqlite3_exec( hDB, "ROLLBACK", NULL, NULL, &pszErrMsg );
    1030               1 :     if( rc != SQLITE_OK )
    1031                 :     {
    1032                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1033                 :                   "ROLLBACK transaction failed: %s",
    1034               0 :                   pszErrMsg );
    1035               0 :         sqlite3_free( pszErrMsg );
    1036               0 :         return OGRERR_FAILURE;
    1037                 :     }
    1038                 :     
    1039               1 :     return OGRERR_NONE;
    1040                 : }
    1041                 : 
    1042                 : /************************************************************************/
    1043                 : /*                        FlushSoftTransaction()                        */
    1044                 : /*                                                                      */
    1045                 : /*      Force the unwinding of any active transaction, and it's         */
    1046                 : /*      commit.                                                         */
    1047                 : /************************************************************************/
    1048                 : 
    1049               0 : OGRErr OGRSQLiteDataSource::FlushSoftTransaction()
    1050                 : 
    1051                 : {
    1052               0 :     if( nSoftTransactionLevel <= 0 )
    1053               0 :         return OGRERR_NONE;
    1054                 : 
    1055               0 :     nSoftTransactionLevel = 1;
    1056                 : 
    1057               0 :     return SoftCommit();
    1058                 : }
    1059                 : 
    1060                 : /************************************************************************/
    1061                 : /*                             FetchSRSId()                             */
    1062                 : /*                                                                      */
    1063                 : /*      Fetch the id corresponding to an SRS, and if not found, add     */
    1064                 : /*      it to the table.                                                */
    1065                 : /************************************************************************/
    1066                 : 
    1067               3 : int OGRSQLiteDataSource::FetchSRSId( OGRSpatialReference * poSRS )
    1068                 : 
    1069                 : {
    1070               3 :     int                 nSRSId = -1;
    1071               3 :     const char          *pszAuthorityName, *pszAuthorityCode = NULL;
    1072               3 :     CPLString           osCommand;
    1073                 :     char *pszErrMsg;
    1074                 :     int   rc;
    1075                 :     char **papszResult;
    1076                 :     int nRowCount, nColCount;
    1077                 : 
    1078               3 :     if( poSRS == NULL )
    1079               0 :         return -1;
    1080                 : 
    1081               3 :     pszAuthorityName = poSRS->GetAuthorityName(NULL);
    1082                 : 
    1083                 : /* -------------------------------------------------------------------- */
    1084                 : /*      Check whether the EPSG authority code is already mapped to a    */
    1085                 : /*      SRS ID.                                                         */
    1086                 : /* -------------------------------------------------------------------- */
    1087               3 :     if( pszAuthorityName != NULL && strlen(pszAuthorityName) > 0 )
    1088                 :     {
    1089               3 :         pszAuthorityCode = poSRS->GetAuthorityCode(NULL);
    1090                 : 
    1091               3 :         if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
    1092                 :         {
    1093                 :             // XXX: We are using case insensitive comparison for "auth_name"
    1094                 :             // values, because there are variety of options exist. By default
    1095                 :             // the driver uses 'EPSG' in upper case, but SpatiaLite extension
    1096                 :             // uses 'epsg' in lower case.
    1097                 :             osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE "
    1098                 :                               "auth_name = '%s' COLLATE NOCASE AND auth_srid = '%s'",
    1099               3 :                               pszAuthorityName, pszAuthorityCode );
    1100                 : 
    1101                 :             rc = sqlite3_get_table( hDB, osCommand, &papszResult, 
    1102               3 :                                     &nRowCount, &nColCount, &pszErrMsg );
    1103               3 :             if( rc != SQLITE_OK )
    1104                 :             {
    1105                 :                 /* Retry without COLLATE NOCASE which may not be understood by older sqlite3 */
    1106               0 :                 sqlite3_free( pszErrMsg );
    1107                 : 
    1108                 :                 osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE "
    1109                 :                                   "auth_name = '%s' AND auth_srid = '%s'",
    1110               0 :                                   pszAuthorityName, pszAuthorityCode );
    1111                 : 
    1112                 :                 rc = sqlite3_get_table( hDB, osCommand, &papszResult, 
    1113               0 :                                         &nRowCount, &nColCount, &pszErrMsg );
    1114                 : 
    1115                 :                 /* Retry in lower case for SpatiaLite */
    1116               0 :                 if( rc != SQLITE_OK )
    1117                 :                 {
    1118               0 :                     sqlite3_free( pszErrMsg );
    1119                 :                 }
    1120               0 :                 else if ( nRowCount == 0 &&
    1121                 :                           strcmp(pszAuthorityName, "EPSG") == 0)
    1122                 :                 {
    1123                 :                     /* If it's in upper case, look for lower case */
    1124               0 :                     sqlite3_free_table(papszResult);
    1125                 : 
    1126                 :                     osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE "
    1127                 :                                       "auth_name = 'epsg' AND auth_srid = '%s'",
    1128               0 :                                       pszAuthorityCode );
    1129                 : 
    1130                 :                     rc = sqlite3_get_table( hDB, osCommand, &papszResult, 
    1131               0 :                                             &nRowCount, &nColCount, &pszErrMsg );
    1132                 : 
    1133               0 :                     if( rc != SQLITE_OK )
    1134                 :                     {
    1135               0 :                         sqlite3_free( pszErrMsg );
    1136                 :                     }
    1137                 :                 }
    1138                 :             }
    1139                 : 
    1140               3 :             if( rc == SQLITE_OK && nRowCount == 1 )
    1141                 :             {
    1142               1 :                 nSRSId = atoi(papszResult[1]);
    1143               1 :                 sqlite3_free_table(papszResult);
    1144               1 :                 return nSRSId;
    1145                 :             }
    1146               2 :             sqlite3_free_table(papszResult);
    1147                 :         }
    1148                 :     }
    1149                 : 
    1150                 : /* -------------------------------------------------------------------- */
    1151                 : /*      Search for existing record using either WKT definition or       */
    1152                 : /*      PROJ.4 string (SpatiaLite variant).                             */
    1153                 : /* -------------------------------------------------------------------- */
    1154               2 :     CPLString   osSRS;
    1155                 : 
    1156               2 :     if ( !bIsSpatiaLite )
    1157                 :     {
    1158                 : /* -------------------------------------------------------------------- */
    1159                 : /*      Translate SRS to WKT.                                           */
    1160                 : /* -------------------------------------------------------------------- */
    1161               1 :         char    *pszWKT = NULL;
    1162                 : 
    1163               1 :         if( poSRS->exportToWkt( &pszWKT ) != OGRERR_NONE )
    1164               0 :             return -1;
    1165                 : 
    1166               1 :         osSRS = pszWKT;
    1167               1 :         CPLFree( pszWKT );
    1168               1 :         pszWKT = NULL;
    1169                 : 
    1170                 : /* -------------------------------------------------------------------- */
    1171                 : /*      Try to find based on the WKT match.                             */
    1172                 : /* -------------------------------------------------------------------- */
    1173                 :         osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE srtext = '%s'",
    1174               1 :                           osSRS.c_str());
    1175                 :         
    1176                 :         rc = sqlite3_get_table( hDB, osCommand, &papszResult,
    1177               1 :                                 &nRowCount, &nColCount, &pszErrMsg );
    1178               1 :         if( rc != SQLITE_OK )
    1179                 :         {
    1180                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1181               0 :                       "Search for existing SRS by WKT failed: %s", pszErrMsg );
    1182               0 :             sqlite3_free( pszErrMsg );
    1183                 :         }
    1184               1 :         else if( nRowCount == 1 )
    1185                 :         {
    1186               0 :             nSRSId = atoi(papszResult[1]);
    1187               0 :             sqlite3_free_table(papszResult);
    1188               0 :             return nSRSId;
    1189                 :         }
    1190               1 :         sqlite3_free_table(papszResult);
    1191                 :     }
    1192                 : 
    1193                 : /* -------------------------------------------------------------------- */
    1194                 : /*      Handle SpatiaLite flavour of the spatial_ref_sys.               */
    1195                 : /* -------------------------------------------------------------------- */
    1196                 :     else
    1197                 :     {
    1198                 : /* -------------------------------------------------------------------- */
    1199                 : /*      Translate SRS to PROJ.4 string.                                 */
    1200                 : /* -------------------------------------------------------------------- */
    1201               1 :         char    *pszProj4 = NULL;
    1202                 : 
    1203               1 :         if( poSRS->exportToProj4( &pszProj4 ) != OGRERR_NONE )
    1204               0 :             return -1;
    1205                 : 
    1206               1 :         osSRS = pszProj4;
    1207               1 :         CPLFree( pszProj4 );
    1208               1 :         pszProj4 = NULL;
    1209                 : 
    1210                 : /* -------------------------------------------------------------------- */
    1211                 : /*      Try to find based on the WKT match.                             */
    1212                 : /* -------------------------------------------------------------------- */
    1213                 :         osCommand.Printf(
    1214                 :             "SELECT srid FROM spatial_ref_sys WHERE proj4text = '%s'",
    1215               1 :             osSRS.c_str());
    1216                 :         
    1217                 :         rc = sqlite3_get_table( hDB, osCommand, &papszResult,
    1218               1 :                                 &nRowCount, &nColCount, &pszErrMsg );
    1219               1 :         if( rc != SQLITE_OK )
    1220                 :         {
    1221                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1222                 :                       "Search for existing SRS by PROJ.4 string failed: %s",
    1223               0 :                       pszErrMsg );
    1224               0 :             sqlite3_free( pszErrMsg );
    1225                 :         }
    1226               1 :         else if( nRowCount == 1 )
    1227                 :         {
    1228               0 :             nSRSId = atoi(papszResult[1]);
    1229               0 :             sqlite3_free_table(papszResult);
    1230               0 :             return nSRSId;
    1231                 :         }
    1232               1 :         sqlite3_free_table(papszResult);
    1233                 :     }
    1234                 : 
    1235                 : /* -------------------------------------------------------------------- */
    1236                 : /*      If the command actually failed, then the metadata table is      */
    1237                 : /*      likely missing, so we give up.                                  */
    1238                 : /* -------------------------------------------------------------------- */
    1239               2 :     if( rc != SQLITE_OK )
    1240               0 :         return -1;
    1241                 : 
    1242                 : /* -------------------------------------------------------------------- */
    1243                 : /*      If we have an authority code try to assign SRS ID the same      */
    1244                 : /*      as that code.                                                   */
    1245                 : /* -------------------------------------------------------------------- */
    1246               2 :     if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
    1247                 :     {
    1248                 :         osCommand.Printf( "SELECT * FROM spatial_ref_sys WHERE auth_srid='%s'",
    1249               2 :                           pszAuthorityCode );
    1250                 :         rc = sqlite3_get_table( hDB, osCommand, &papszResult,
    1251               2 :                                 &nRowCount, &nColCount, &pszErrMsg );
    1252                 :         
    1253               2 :         if( rc != SQLITE_OK )
    1254                 :         {
    1255                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1256                 :                       "exec(SELECT '%s' FROM spatial_ref_sys) failed: %s",
    1257               0 :                       pszAuthorityCode, pszErrMsg );
    1258               0 :             sqlite3_free( pszErrMsg );
    1259                 :         }
    1260                 : 
    1261                 : /* -------------------------------------------------------------------- */
    1262                 : /*      If there is no SRS ID with such auth_srid, use it as SRS ID.    */
    1263                 : /* -------------------------------------------------------------------- */
    1264               2 :         if ( nRowCount < 1 )
    1265               2 :             nSRSId = atoi(pszAuthorityCode);
    1266               2 :         sqlite3_free_table(papszResult);
    1267                 :     }
    1268                 : 
    1269                 : /* -------------------------------------------------------------------- */
    1270                 : /*      Otherwise get the current maximum srid in the srs table.        */
    1271                 : /* -------------------------------------------------------------------- */
    1272               2 :     if ( nSRSId == -1 )
    1273                 :     {
    1274                 :         rc = sqlite3_get_table( hDB, "SELECT MAX(srid) FROM spatial_ref_sys", 
    1275                 :                                 &papszResult, &nRowCount, &nColCount,
    1276               0 :                                 &pszErrMsg );
    1277                 :         
    1278               0 :         if( rc != SQLITE_OK )
    1279                 :         {
    1280                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1281               0 :                       "SELECT of the maximum SRS ID failed: %s", pszErrMsg );
    1282               0 :             sqlite3_free( pszErrMsg );
    1283               0 :             return -1;
    1284                 :         }
    1285                 : 
    1286               0 :         if ( nRowCount < 1 || !papszResult[1] )
    1287               0 :             nSRSId = 50000;
    1288                 :         else
    1289               0 :             nSRSId = atoi(papszResult[1]) + 1;  // Insert as the next SRS ID
    1290               0 :         sqlite3_free_table(papszResult);
    1291                 :     }
    1292                 : 
    1293                 : /* -------------------------------------------------------------------- */
    1294                 : /*      Try adding the SRS to the SRS table.                            */
    1295                 : /* -------------------------------------------------------------------- */
    1296               2 :     if ( !bIsSpatiaLite )
    1297                 :     {
    1298               1 :         if( pszAuthorityName != NULL )
    1299                 :         {
    1300                 :             osCommand.Printf(
    1301                 :                 "INSERT INTO spatial_ref_sys (srid,srtext,auth_name,auth_srid) "
    1302                 :                 "                     VALUES (%d, '%s', '%s', '%s')",
    1303                 :                 nSRSId, osSRS.c_str(), 
    1304               1 :                 pszAuthorityName, poSRS->GetAuthorityCode(NULL) );
    1305                 :         }
    1306                 :         else
    1307                 :         {
    1308                 :             osCommand.Printf(
    1309                 :                 "INSERT INTO spatial_ref_sys (srid,srtext) "
    1310                 :                 "                     VALUES (%d, '%s')",
    1311               0 :                 nSRSId, osSRS.c_str() );
    1312                 :         }
    1313                 :     }
    1314                 :     else
    1315                 :     {
    1316               1 :         const char  *pszProjCS = poSRS->GetAttrValue("PROJCS");
    1317                 : 
    1318               1 :         if( pszAuthorityName != NULL )
    1319                 :         {
    1320               1 :             if ( pszProjCS )
    1321                 :                 osCommand.Printf(
    1322                 :                     "INSERT INTO spatial_ref_sys "
    1323                 :                     "(srid, auth_name, auth_srid, ref_sys_name, proj4text) "
    1324                 :                     "VALUES (%d, '%s', '%s', '%s', '%s')",
    1325                 :                     nSRSId, pszAuthorityName,
    1326               0 :                     poSRS->GetAuthorityCode(NULL), pszProjCS, osSRS.c_str() );
    1327                 :             else
    1328                 :                 osCommand.Printf(
    1329                 :                     "INSERT INTO spatial_ref_sys "
    1330                 :                     "(srid, auth_name, auth_srid, proj4text) "
    1331                 :                     "VALUES (%d, '%s', '%s', '%s')",
    1332                 :                     nSRSId, pszAuthorityName,
    1333               1 :                     poSRS->GetAuthorityCode(NULL), osSRS.c_str() );
    1334                 :         }
    1335                 :         else
    1336                 :         {
    1337               0 :             if ( pszProjCS )
    1338                 :                 osCommand.Printf(
    1339                 :                     "INSERT INTO spatial_ref_sys "
    1340                 :                     "(srid, ref_sys_name, proj4text) VALUES (%d, '%s', '%s')",
    1341               0 :                     nSRSId, pszProjCS, osSRS.c_str() );
    1342                 :             else
    1343                 :                 osCommand.Printf(
    1344                 :                     "INSERT INTO spatial_ref_sys "
    1345                 :                     "(srid, proj4text) VALUES (%d, '%s')",
    1346               0 :                     nSRSId, osSRS.c_str() );
    1347                 :         }
    1348                 :     }
    1349                 : 
    1350               2 :     rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
    1351               2 :     if( rc != SQLITE_OK )
    1352                 :     {
    1353                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1354                 :                   "Unable to insert SRID (%s): %s",
    1355               0 :                   osCommand.c_str(), pszErrMsg );
    1356               0 :         sqlite3_free( pszErrMsg );
    1357               0 :         return FALSE;
    1358                 :     }
    1359                 : 
    1360               2 :     return nSRSId;
    1361                 : }
    1362                 : 
    1363                 : /************************************************************************/
    1364                 : /*                              FetchSRS()                              */
    1365                 : /*                                                                      */
    1366                 : /*      Return a SRS corresponding to a particular id.  Note that       */
    1367                 : /*      reference counting should be honoured on the returned           */
    1368                 : /*      OGRSpatialReference, as handles may be cached.                  */
    1369                 : /************************************************************************/
    1370                 : 
    1371              45 : OGRSpatialReference *OGRSQLiteDataSource::FetchSRS( int nId )
    1372                 : 
    1373                 : {
    1374              45 :     if( nId <= 0 )
    1375              29 :         return NULL;
    1376                 : 
    1377                 : /* -------------------------------------------------------------------- */
    1378                 : /*      First, we look through our SRID cache, is it there?             */
    1379                 : /* -------------------------------------------------------------------- */
    1380                 :     int  i;
    1381                 : 
    1382              16 :     for( i = 0; i < nKnownSRID; i++ )
    1383                 :     {
    1384               4 :         if( panSRID[i] == nId )
    1385               4 :             return papoSRS[i];
    1386                 :     }
    1387                 : 
    1388                 : /* -------------------------------------------------------------------- */
    1389                 : /*      Try looking up in spatial_ref_sys table.                        */
    1390                 : /* -------------------------------------------------------------------- */
    1391                 :     char *pszErrMsg;
    1392                 :     int   rc;
    1393                 :     char **papszResult;
    1394                 :     int nRowCount, nColCount;
    1395              12 :     CPLString osCommand;
    1396              12 :     OGRSpatialReference *poSRS = NULL;
    1397                 : 
    1398                 :     osCommand.Printf( "SELECT srtext FROM spatial_ref_sys WHERE srid = %d",
    1399              12 :                       nId );
    1400                 :     rc = sqlite3_get_table( hDB, osCommand, 
    1401              12 :                             &papszResult, &nRowCount, &nColCount, &pszErrMsg );
    1402                 : 
    1403              12 :     if ( rc == SQLITE_OK )
    1404                 :     {
    1405               5 :         if( nRowCount < 1 )
    1406                 :         {
    1407               0 :             sqlite3_free_table(papszResult);
    1408               0 :             return NULL;
    1409                 :         }
    1410                 : 
    1411               5 :         char** papszRow = papszResult + nColCount;
    1412               5 :         CPLString osWKT = papszRow[0];
    1413                 :         
    1414                 : /* -------------------------------------------------------------------- */
    1415                 : /*      Translate into a spatial reference.                             */
    1416                 : /* -------------------------------------------------------------------- */
    1417               5 :         char *pszWKT = (char *) osWKT.c_str();
    1418                 : 
    1419               5 :         poSRS = new OGRSpatialReference();
    1420              10 :         if( poSRS->importFromWkt( &pszWKT ) != OGRERR_NONE )
    1421                 :         {
    1422               0 :             delete poSRS;
    1423               0 :             poSRS = NULL;
    1424                 :         }
    1425                 : 
    1426               5 :         sqlite3_free_table(papszResult);
    1427                 :     }
    1428                 : 
    1429                 : /* -------------------------------------------------------------------- */
    1430                 : /*      Next try SpatiaLite flavour. SpatiaLite uses PROJ.4 strings     */
    1431                 : /*      in 'proj4text' column instead of WKT in 'srtext'.               */
    1432                 : /* -------------------------------------------------------------------- */
    1433                 :     else
    1434                 :     {
    1435               7 :         sqlite3_free( pszErrMsg );
    1436               7 :         pszErrMsg = NULL;
    1437                 : 
    1438                 :         osCommand.Printf(
    1439               7 :             "SELECT proj4text, auth_name, auth_srid FROM spatial_ref_sys WHERE srid = %d", nId );
    1440                 :         rc = sqlite3_get_table( hDB, osCommand, 
    1441                 :                                 &papszResult, &nRowCount,
    1442               7 :                                 &nColCount, &pszErrMsg );
    1443               7 :         if ( rc == SQLITE_OK )
    1444                 :         {
    1445               7 :             if( nRowCount < 1 )
    1446                 :             {
    1447               0 :                 sqlite3_free_table(papszResult);
    1448               0 :                 return NULL;
    1449                 :             }
    1450                 : 
    1451                 : /* -------------------------------------------------------------------- */
    1452                 : /*      Translate into a spatial reference.                             */
    1453                 : /* -------------------------------------------------------------------- */
    1454               7 :             poSRS = new OGRSpatialReference();
    1455                 :             
    1456               7 :             char** papszRow = papszResult + nColCount;
    1457                 :             
    1458               7 :             const char* pszProj4Text = papszRow[0];
    1459               7 :             const char* pszAuthName = papszRow[1];
    1460               7 :             int nAuthSRID = atoi(papszRow[2]);
    1461                 :             
    1462                 :             /* Try first from EPSG code */
    1463              14 :             if (EQUAL(pszAuthName, "EPSG") &&
    1464                 :                 poSRS->importFromEPSG( nAuthSRID ) == OGRERR_NONE)
    1465                 :             {
    1466                 :                 /* Do nothing */
    1467                 :             }
    1468                 :             /* Then from Proj4 string */
    1469               0 :             else if( poSRS->importFromProj4( pszProj4Text ) != OGRERR_NONE )
    1470                 :             {
    1471               0 :                 delete poSRS;
    1472               0 :                 poSRS = NULL;
    1473                 :             }
    1474                 : 
    1475               7 :             sqlite3_free_table(papszResult);
    1476                 :         }
    1477                 : 
    1478                 : /* -------------------------------------------------------------------- */
    1479                 : /*      No success, report an error.                                    */
    1480                 : /* -------------------------------------------------------------------- */
    1481                 :         else
    1482                 :         {
    1483                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1484               0 :                       "%s: %s", osCommand.c_str(), pszErrMsg );
    1485               0 :             sqlite3_free( pszErrMsg );
    1486               0 :             return NULL;
    1487                 :         }
    1488                 :     }
    1489                 : 
    1490                 : /* -------------------------------------------------------------------- */
    1491                 : /*      Add to the cache.                                               */
    1492                 : /* -------------------------------------------------------------------- */
    1493              12 :     panSRID = (int *) CPLRealloc(panSRID,sizeof(int) * (nKnownSRID+1) );
    1494                 :     papoSRS = (OGRSpatialReference **)
    1495              12 :         CPLRealloc(papoSRS, sizeof(void*) * (nKnownSRID + 1) );
    1496              12 :     panSRID[nKnownSRID] = nId;
    1497              12 :     papoSRS[nKnownSRID] = poSRS;
    1498              12 :     nKnownSRID++;
    1499                 : 
    1500              12 :     return poSRS;
    1501                 : }

Generated by: LCOV version 1.7