LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mysql - ogrmysqldatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 384 277 72.1 %
Date: 2012-12-26 Functions: 20 15 75.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrmysqldatasource.cpp 24947 2012-09-22 09:54:23Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGRMySQLDataSource class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  * Author:   Howard Butler, hobu@hobu.net
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : 
      32                 : #include <string>
      33                 : #include "ogr_mysql.h"
      34                 : #include <my_sys.h>
      35                 : 
      36                 : #include "cpl_conv.h"
      37                 : #include "cpl_string.h"
      38                 : 
      39                 : CPL_CVSID("$Id: ogrmysqldatasource.cpp 24947 2012-09-22 09:54:23Z rouault $");
      40                 : /************************************************************************/
      41                 : /*                         OGRMySQLDataSource()                         */
      42                 : /************************************************************************/
      43                 : 
      44             213 : OGRMySQLDataSource::OGRMySQLDataSource()
      45                 : 
      46                 : {
      47             213 :     pszName = NULL;
      48             213 :     papoLayers = NULL;
      49             213 :     nLayers = 0;
      50             213 :     hConn = 0;
      51             213 :     nSoftTransactionLevel = 0;
      52                 : 
      53             213 :     nKnownSRID = 0;
      54             213 :     panSRID = NULL;
      55             213 :     papoSRS = NULL;
      56                 : 
      57             213 :     poLongResultLayer = NULL;
      58             213 : }
      59                 : 
      60                 : /************************************************************************/
      61                 : /*                        ~OGRMySQLDataSource()                         */
      62                 : /************************************************************************/
      63                 : 
      64             213 : OGRMySQLDataSource::~OGRMySQLDataSource()
      65                 : 
      66                 : {
      67                 :     int         i;
      68                 : 
      69             213 :     InterruptLongResult();
      70                 : 
      71             213 :     CPLFree( pszName );
      72                 : 
      73             227 :     for( i = 0; i < nLayers; i++ )
      74              14 :         delete papoLayers[i];
      75                 :     
      76             213 :     CPLFree( papoLayers );
      77                 : 
      78             213 :     if( hConn != NULL )
      79               1 :         mysql_close( hConn );
      80                 : 
      81             214 :     for( i = 0; i < nKnownSRID; i++ )
      82                 :     {
      83               1 :         if( papoSRS[i] != NULL )
      84               1 :             papoSRS[i]->Release();
      85                 :     }
      86             213 :     CPLFree( panSRID );
      87             213 :     CPLFree( papoSRS );
      88             213 : }
      89                 : 
      90                 : /************************************************************************/
      91                 : /*                            ReportError()                             */
      92                 : /************************************************************************/
      93                 : 
      94               1 : void OGRMySQLDataSource::ReportError( const char *pszDescription )
      95                 : 
      96                 : {
      97               1 :     if( pszDescription )
      98                 :         CPLError( CE_Failure, CPLE_AppDefined, 
      99                 :                   "MySQL error message:%s Description: %s", 
     100                 :                   mysql_error( hConn ), 
     101               1 :                   pszDescription );
     102                 :     else
     103                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     104               0 :                   "%s", mysql_error( hConn ) );
     105               1 : }
     106                 : 
     107                 : /************************************************************************/
     108                 : /*                                Open()                                */
     109                 : /************************************************************************/
     110                 : 
     111             213 : int OGRMySQLDataSource::Open( const char * pszNewName, int bUpdate,
     112                 :                               int bTestOpen )
     113                 : 
     114                 : {
     115             213 :     CPLAssert( nLayers == 0 );
     116                 : 
     117                 : /* -------------------------------------------------------------------- */
     118                 : /*      Verify MySQL prefix.                                            */
     119                 : /* -------------------------------------------------------------------- */
     120             213 :     if( !EQUALN(pszNewName,"MYSQL:",6) )
     121                 :     {
     122             212 :         if( !bTestOpen )
     123                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     124                 :                       "%s does not conform to MySQL naming convention,"
     125                 :                       " MYSQL:dbname[, user=..][,password=..][,host=..][,port=..][tables=table;table;...]",
     126               0 :                       pszNewName );
     127             212 :         return FALSE;
     128                 :     }
     129                 :     
     130                 : /* -------------------------------------------------------------------- */
     131                 : /*      Use options process to get .my.cnf file contents.               */
     132                 : /* -------------------------------------------------------------------- */
     133               1 :     int nPort = 0, i;
     134               1 :     char **papszTableNames=NULL;
     135               1 :     std::string oHost, oPassword, oUser, oDB;
     136               1 :     char *apszArgv[2] = { (char*) "org", NULL };
     137               1 :     char **papszArgv = apszArgv;
     138               1 :     int  nArgc = 1;
     139               1 :     const char *client_groups[] = {"client", "ogr", NULL };
     140                 : 
     141               1 :     my_init(); // I hope there is no problem with calling this multiple times!
     142               1 :     load_defaults( "my", client_groups, &nArgc, &papszArgv );
     143                 : 
     144               4 :     for( i = 0; i < nArgc; i++ )
     145                 :     {
     146               3 :         if( EQUALN(papszArgv[i],"--user=",7) )
     147               0 :             oUser = papszArgv[i] + 7;
     148               3 :         else if( EQUALN(papszArgv[i],"--host=",7) )
     149               0 :             oHost = papszArgv[i] + 7;
     150               3 :         else if( EQUALN(papszArgv[i],"--password=",11) )
     151               0 :             oPassword = papszArgv[i] + 11;
     152               3 :         else if( EQUALN(papszArgv[i],"--port=",7) )
     153               1 :             nPort = atoi(papszArgv[i] + 7);
     154                 :     }
     155                 : 
     156                 :     // cleanup
     157               1 :     free_defaults( papszArgv );
     158                 : 
     159                 : /* -------------------------------------------------------------------- */
     160                 : /*      Parse out connection information.                               */
     161                 : /* -------------------------------------------------------------------- */
     162                 :     char **papszItems = CSLTokenizeString2( pszNewName+6, ",", 
     163               1 :                                             CSLT_HONOURSTRINGS );
     164                 : 
     165               1 :     if( CSLCount(papszItems) < 1 )
     166                 :     {
     167               0 :         CSLDestroy( papszItems );
     168                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     169               0 :                   "MYSQL: request missing databasename." );
     170               0 :         return FALSE;
     171                 :     }
     172                 : 
     173               1 :     oDB = papszItems[0];
     174                 : 
     175               1 :     for( i = 1; papszItems[i] != NULL; i++ )
     176                 :     {
     177               0 :         if( EQUALN(papszItems[i],"user=",5) )
     178               0 :             oUser = papszItems[i] + 5;
     179               0 :         else if( EQUALN(papszItems[i],"password=",9) )
     180               0 :             oPassword = papszItems[i] + 9;
     181               0 :         else if( EQUALN(papszItems[i],"host=",5) )
     182               0 :             oHost = papszItems[i] + 5;
     183               0 :         else if( EQUALN(papszItems[i],"port=",5) )
     184               0 :             nPort = atoi(papszItems[i] + 5);
     185               0 :         else if( EQUALN(papszItems[i],"tables=",7) )
     186                 :         {
     187                 :             papszTableNames = CSLTokenizeStringComplex( 
     188               0 :                 papszItems[i] + 7, ";", FALSE, FALSE );
     189                 :         }
     190                 :         else
     191                 :             CPLError( CE_Warning, CPLE_AppDefined, 
     192               0 :                       "'%s' in MYSQL datasource definition not recognised and ignored.", papszItems[i] );
     193                 :     }
     194                 : 
     195               1 :     CSLDestroy( papszItems );
     196                 : 
     197                 : /* -------------------------------------------------------------------- */
     198                 : /*      Try to establish connection.                                    */
     199                 : /* -------------------------------------------------------------------- */
     200               1 :     hConn = mysql_init( NULL );
     201                 : 
     202               1 :     if( hConn == NULL )
     203                 :     {
     204                 :         CPLError( CE_Failure, CPLE_AppDefined,
     205               0 :                   "mysql_init() failed." );
     206                 :     }
     207                 : 
     208                 : /* -------------------------------------------------------------------- */
     209                 : /*      Set desired options on the connection: charset and timeout.     */
     210                 : /* -------------------------------------------------------------------- */
     211               1 :     if( hConn )
     212                 :     {
     213                 :         const char *pszTimeoutLength = 
     214               1 :             CPLGetConfigOption( "MYSQL_TIMEOUT", "0" );  
     215                 :         
     216               1 :         unsigned int timeout = atoi(pszTimeoutLength);        
     217               1 :         mysql_options(hConn, MYSQL_OPT_CONNECT_TIMEOUT, (char*)&timeout);
     218                 : 
     219               1 :         mysql_options(hConn, MYSQL_SET_CHARSET_NAME, "utf8" );
     220                 :     }
     221                 :     
     222                 : /* -------------------------------------------------------------------- */
     223                 : /*      Perform connection.                                             */
     224                 : /* -------------------------------------------------------------------- */
     225               1 :     if( hConn
     226                 :         && mysql_real_connect( hConn, 
     227                 :                                oHost.length() ? oHost.c_str() : NULL,
     228                 :                                oUser.length() ? oUser.c_str() : NULL,
     229                 :                                oPassword.length() ? oPassword.c_str() : NULL,
     230                 :                                oDB.length() ? oDB.c_str() : NULL,
     231                 :                                nPort, NULL, CLIENT_INTERACTIVE ) == NULL )
     232                 :     {
     233                 :         CPLError( CE_Failure, CPLE_AppDefined,
     234                 :                   "MySQL connect failed for: %s\n%s", 
     235               0 :                   pszNewName + 6, mysql_error( hConn ) );
     236               0 :         mysql_close( hConn );
     237               0 :         hConn = NULL;
     238                 :     }
     239                 : 
     240               1 :     if( hConn == NULL )
     241                 :     {
     242               0 :         CSLDestroy( papszTableNames );
     243               0 :         return FALSE;
     244                 :     }
     245                 :     else
     246                 :     {
     247                 :         // Enable automatic reconnection
     248                 :         // Must be called after mysql_real_connect() on MySQL < 5.0.19
     249                 :         // and at any point on more recent versions.
     250               1 :         my_bool reconnect = 1;
     251               1 :         mysql_options(hConn, MYSQL_OPT_RECONNECT, &reconnect);
     252                 :     }
     253                 :     
     254               1 :     pszName = CPLStrdup( pszNewName );
     255                 :     
     256               1 :     bDSUpdate = bUpdate;
     257                 : 
     258                 : /* -------------------------------------------------------------------- */
     259                 : /*      Get a list of available tables.                                 */
     260                 : /* -------------------------------------------------------------------- */
     261               1 :     if( papszTableNames == NULL )
     262                 :     {
     263                 :         MYSQL_RES *hResultSet;
     264                 :         MYSQL_ROW papszRow;
     265                 : 
     266               1 :         if( mysql_query( hConn, "SHOW TABLES" ) )
     267                 :         {
     268               0 :             ReportError( "SHOW TABLES Failed" );
     269               0 :             return FALSE;
     270                 :         }
     271                 : 
     272               1 :         hResultSet = mysql_store_result( hConn );
     273               1 :         if( hResultSet == NULL )
     274                 :         {
     275               0 :             ReportError( "mysql_store_result() failed on SHOW TABLES result.");
     276               0 :             return FALSE;
     277                 :         }
     278                 :     
     279              12 :         while( (papszRow = mysql_fetch_row( hResultSet )) != NULL )
     280                 :         {
     281              10 :             if( papszRow[0] == NULL )
     282               0 :                 continue;
     283                 : 
     284              20 :             if( EQUAL(papszRow[0],"spatial_ref_sys")
     285              10 :                 || EQUAL(papszRow[0],"geometry_columns") )
     286               0 :                 continue;
     287                 : 
     288              10 :             papszTableNames = CSLAddString(papszTableNames, papszRow[0] );
     289                 :         }
     290                 : 
     291               1 :         mysql_free_result( hResultSet );
     292                 :     }
     293                 : 
     294                 : /* -------------------------------------------------------------------- */
     295                 : /*      Get the schema of the available tables.                         */
     296                 : /* -------------------------------------------------------------------- */
     297                 :     int iRecord;
     298                 : 
     299              22 :     for( iRecord = 0; 
     300              11 :          papszTableNames != NULL && papszTableNames[iRecord] != NULL;
     301                 :          iRecord++ )
     302                 :     {
     303                 :         //  FIXME: This should be fixed to deal with tables 
     304                 :         //  for which we can't open because the name is bad/ 
     305              10 :         OpenTable( papszTableNames[iRecord], bUpdate, FALSE );
     306                 :     }
     307                 : 
     308               1 :     CSLDestroy( papszTableNames );
     309                 :     
     310               1 :     return nLayers > 0 || bUpdate;
     311                 : }
     312                 : 
     313                 : /************************************************************************/
     314                 : /*                             OpenTable()                              */
     315                 : /************************************************************************/
     316                 : 
     317              10 : int OGRMySQLDataSource::OpenTable( const char *pszNewName, int bUpdate,
     318                 :                                 int bTestOpen )
     319                 : 
     320                 : {
     321                 : /* -------------------------------------------------------------------- */
     322                 : /*      Create the layer object.                                        */
     323                 : /* -------------------------------------------------------------------- */
     324                 :     OGRMySQLTableLayer  *poLayer;
     325                 :     OGRErr eErr;
     326                 : 
     327              10 :     poLayer = new OGRMySQLTableLayer( this, pszNewName, bUpdate );
     328              10 :     eErr = poLayer->Initialize(pszNewName);
     329              10 :     if (eErr == OGRERR_FAILURE)
     330               0 :         return FALSE;
     331                 : 
     332                 : /* -------------------------------------------------------------------- */
     333                 : /*      Add layer to data source layer list.                            */
     334                 : /* -------------------------------------------------------------------- */
     335                 :     papoLayers = (OGRMySQLLayer **)
     336              10 :         CPLRealloc( papoLayers,  sizeof(OGRMySQLLayer *) * (nLayers+1) );
     337              10 :     papoLayers[nLayers++] = poLayer;
     338                 :     
     339              10 :     return TRUE;
     340                 : }
     341                 : 
     342                 : /************************************************************************/
     343                 : /*                           TestCapability()                           */
     344                 : /************************************************************************/
     345                 : 
     346               0 : int OGRMySQLDataSource::TestCapability( const char * pszCap )
     347                 : 
     348                 : {
     349                 :   
     350               0 :     if( EQUAL(pszCap, ODsCCreateLayer) )
     351               0 :         return TRUE;
     352               0 :   if( EQUAL(pszCap, ODsCDeleteLayer))
     353               0 :     return TRUE;
     354                 :     else
     355               0 :         return FALSE;
     356                 : }
     357                 : 
     358                 : /************************************************************************/
     359                 : /*                              GetLayer()                              */
     360                 : /************************************************************************/
     361                 : 
     362              45 : OGRLayer *OGRMySQLDataSource::GetLayer( int iLayer )
     363                 : 
     364                 : {
     365              45 :     if( iLayer < 0 || iLayer >= nLayers )
     366               0 :         return NULL;
     367                 :     else
     368              45 :         return papoLayers[iLayer];
     369                 : }
     370                 : 
     371                 : 
     372                 : /************************************************************************/
     373                 : /*                      InitializeMetadataTables()                      */
     374                 : /*                                                                      */
     375                 : /*      Create the metadata tables (SPATIAL_REF_SYS and                 */
     376                 : /*      GEOMETRY_COLUMNS). This method "does no harm" if the tables     */
     377                 : /*      exist and can be called at will.                                */
     378                 : /************************************************************************/
     379                 : 
     380               4 : OGRErr OGRMySQLDataSource::InitializeMetadataTables()
     381                 : 
     382                 : {
     383                 :     const char*      pszCommand;
     384                 :     MYSQL_RES       *hResult;
     385               4 :     OGRErr      eErr = OGRERR_NONE;
     386                 :  
     387               4 :     pszCommand = "DESCRIBE geometry_columns";
     388               4 :     if( mysql_query(GetConn(), pszCommand ) )
     389                 :     {
     390                 :         pszCommand =
     391                 :                 "CREATE TABLE geometry_columns "
     392                 :                 "( F_TABLE_CATALOG VARCHAR(256), "
     393                 :                 "F_TABLE_SCHEMA VARCHAR(256), "
     394                 :                 "F_TABLE_NAME VARCHAR(256) NOT NULL," 
     395                 :                 "F_GEOMETRY_COLUMN VARCHAR(256) NOT NULL, "
     396                 :                 "COORD_DIMENSION INT, "
     397                 :                 "SRID INT,"
     398               1 :                 "TYPE VARCHAR(256) NOT NULL)";
     399               1 :         if( mysql_query(GetConn(), pszCommand ) )
     400                 :         {
     401               0 :             ReportError( pszCommand );
     402               0 :             eErr = OGRERR_FAILURE;
     403                 :         }
     404                 :         else
     405               1 :             CPLDebug("MYSQL","Creating geometry_columns metadata table");
     406                 :  
     407                 :     }
     408                 :  
     409                 :     // make sure to attempt to free results of successful queries
     410               4 :     hResult = mysql_store_result( GetConn() );
     411               4 :     if( hResult != NULL )
     412                 :     {
     413               3 :         mysql_free_result( hResult );
     414               3 :         hResult = NULL;   
     415                 :     }
     416                 :  
     417               4 :     pszCommand = "DESCRIBE spatial_ref_sys";
     418               4 :     if( mysql_query(GetConn(), pszCommand ) )
     419                 :     {
     420                 :         pszCommand =
     421                 :                 "CREATE TABLE spatial_ref_sys "
     422                 :                 "(SRID INT NOT NULL, "
     423                 :                 "AUTH_NAME VARCHAR(256), "
     424                 :                 "AUTH_SRID INT, "
     425               1 :                 "SRTEXT VARCHAR(2048))";
     426               1 :         if( mysql_query(GetConn(), pszCommand ) )
     427                 :         {
     428               0 :             ReportError( pszCommand );
     429               0 :             eErr = OGRERR_FAILURE;
     430                 :         }
     431                 :         else
     432               1 :             CPLDebug("MYSQL","Creating spatial_ref_sys metadata table");
     433                 :  
     434                 :     }    
     435                 :  
     436                 :     // make sure to attempt to free results of successful queries
     437               4 :     hResult = mysql_store_result( GetConn() );
     438               4 :     if( hResult != NULL )
     439                 :     {
     440               3 :         mysql_free_result( hResult );
     441               3 :         hResult = NULL;
     442                 :     }
     443                 :  
     444               4 :     return eErr;
     445                 : }
     446                 : 
     447                 : /************************************************************************/
     448                 : /*                              FetchSRS()                              */
     449                 : /*                                                                      */
     450                 : /*      Return a SRS corresponding to a particular id.  Note that       */
     451                 : /*      reference counting should be honoured on the returned           */
     452                 : /*      OGRSpatialReference, as handles may be cached.                  */
     453                 : /************************************************************************/
     454                 : 
     455               1 : OGRSpatialReference *OGRMySQLDataSource::FetchSRS( int nId )
     456                 : {
     457                 :     char         szCommand[128];
     458                 :     char           **papszRow;  
     459                 :     MYSQL_RES       *hResult;
     460                 :             
     461               1 :     if( nId < 0 )
     462               0 :         return NULL;
     463                 : 
     464                 : /* -------------------------------------------------------------------- */
     465                 : /*      First, we look through our SRID cache, is it there?             */
     466                 : /* -------------------------------------------------------------------- */
     467                 :     int  i;
     468                 : 
     469               1 :     for( i = 0; i < nKnownSRID; i++ )
     470                 :     {
     471               0 :         if( panSRID[i] == nId )
     472               0 :             return papoSRS[i];
     473                 :     }
     474                 : 
     475               1 :     OGRSpatialReference *poSRS = NULL;
     476                 :  
     477                 :     // make sure to attempt to free any old results
     478               1 :     hResult = mysql_store_result( GetConn() );
     479               1 :     if( hResult != NULL )
     480               0 :         mysql_free_result( hResult );
     481               1 :     hResult = NULL;   
     482                 :                         
     483                 :     sprintf( szCommand,
     484                 :          "SELECT srtext FROM spatial_ref_sys WHERE srid = %d",
     485               1 :          nId );
     486                 :     
     487               1 :     if( !mysql_query( GetConn(), szCommand ) )
     488               1 :         hResult = mysql_store_result( GetConn() );
     489                 :         
     490               1 :     char  *pszWKT = NULL;
     491               1 :     papszRow = NULL;
     492                 :     
     493                 : 
     494               1 :     if( hResult != NULL )
     495               1 :         papszRow = mysql_fetch_row( hResult );
     496                 : 
     497               1 :     if( papszRow != NULL && papszRow[0] != NULL )
     498                 :     {
     499               1 :         pszWKT = CPLStrdup(papszRow[0]);
     500                 :     }
     501                 : 
     502               1 :     if( hResult != NULL )
     503               1 :         mysql_free_result( hResult );
     504               1 :     hResult = NULL;
     505                 : 
     506               1 :     poSRS = new OGRSpatialReference();
     507               1 :     char* pszWKTOri = pszWKT;
     508               2 :     if( pszWKT == NULL || poSRS->importFromWkt( &pszWKT ) != OGRERR_NONE )
     509                 :     {
     510               0 :         delete poSRS;
     511               0 :         poSRS = NULL;
     512                 :     }
     513                 : 
     514               1 :     CPLFree(pszWKTOri);
     515                 : 
     516                 : /* -------------------------------------------------------------------- */
     517                 : /*      Add to the cache.                                               */
     518                 : /* -------------------------------------------------------------------- */
     519               1 :     panSRID = (int *) CPLRealloc(panSRID,sizeof(int) * (nKnownSRID+1) );
     520                 :     papoSRS = (OGRSpatialReference **) 
     521               1 :         CPLRealloc(papoSRS, sizeof(void*) * (nKnownSRID + 1) );
     522               1 :     panSRID[nKnownSRID] = nId;
     523               1 :     papoSRS[nKnownSRID] = poSRS;
     524               1 :     nKnownSRID ++;
     525                 : 
     526               1 :     return poSRS;
     527                 : }
     528                 : 
     529                 : 
     530                 : 
     531                 : /************************************************************************/
     532                 : /*                             FetchSRSId()                             */
     533                 : /*                                                                      */
     534                 : /*      Fetch the id corresponding to an SRS, and if not found, add     */
     535                 : /*      it to the table.                                                */
     536                 : /************************************************************************/
     537                 : 
     538               1 : int OGRMySQLDataSource::FetchSRSId( OGRSpatialReference * poSRS )
     539                 : 
     540                 : {
     541                 :     char           **papszRow;  
     542               1 :     MYSQL_RES       *hResult=NULL;
     543                 :     
     544               1 :     CPLString            osCommand;
     545               1 :     char                *pszWKT = NULL;
     546                 :     int                 nSRSId;
     547                 : 
     548               1 :     if( poSRS == NULL )
     549               0 :         return -1;
     550                 : 
     551                 : /* -------------------------------------------------------------------- */
     552                 : /*      Translate SRS to WKT.                                           */
     553                 : /* -------------------------------------------------------------------- */
     554               1 :     if( poSRS->exportToWkt( &pszWKT ) != OGRERR_NONE )
     555               0 :         return -1;
     556                 :     
     557                 : /* -------------------------------------------------------------------- */
     558                 : /*      Try to find in the existing table.                              */
     559                 : /* -------------------------------------------------------------------- */
     560                 :     osCommand.Printf( 
     561                 :              "SELECT srid FROM spatial_ref_sys WHERE srtext = '%s'",
     562               1 :              pszWKT );
     563                 : 
     564               1 :     if( !mysql_query( GetConn(), osCommand ) )
     565               1 :         hResult = mysql_store_result( GetConn() );
     566                 : 
     567               1 :     if (!mysql_num_rows(hResult))
     568                 :     {
     569               1 :         CPLDebug("MYSQL", "No rows exist currently exist in spatial_ref_sys");
     570               1 :         mysql_free_result( hResult );
     571               1 :         hResult = NULL;
     572                 :     }
     573               1 :     papszRow = NULL;
     574               1 :     if( hResult != NULL )
     575               0 :         papszRow = mysql_fetch_row( hResult );
     576                 :         
     577               1 :     if( papszRow != NULL && papszRow[0] != NULL )
     578                 :     {
     579               0 :         nSRSId = atoi(papszRow[0]);
     580               0 :         if( hResult != NULL )
     581               0 :             mysql_free_result( hResult );
     582               0 :         hResult = NULL;
     583               0 :         CPLFree(pszWKT);
     584               0 :         return nSRSId;
     585                 :     }
     586                 : 
     587                 :     // make sure to attempt to free results of successful queries
     588               1 :     hResult = mysql_store_result( GetConn() );
     589               1 :     if( hResult != NULL )
     590               0 :         mysql_free_result( hResult );
     591               1 :     hResult = NULL;
     592                 : 
     593                 : /* -------------------------------------------------------------------- */
     594                 : /*      Get the current maximum srid in the srs table.                  */
     595                 : /* -------------------------------------------------------------------- */
     596               1 :     osCommand = "SELECT MAX(srid) FROM spatial_ref_sys";
     597               1 :     if( !mysql_query( GetConn(), osCommand ) )
     598                 :     {
     599               1 :         hResult = mysql_store_result( GetConn() );
     600               1 :         papszRow = mysql_fetch_row( hResult );
     601                 :     }
     602                 :         
     603               1 :     if( papszRow != NULL && papszRow[0] != NULL )
     604                 :     {
     605               0 :         nSRSId = atoi(papszRow[0]) + 1;
     606                 :     }
     607                 :     else
     608               1 :         nSRSId = 1;
     609                 : 
     610               1 :     if( hResult != NULL )
     611               1 :         mysql_free_result( hResult );
     612               1 :     hResult = NULL;
     613                 : 
     614                 : /* -------------------------------------------------------------------- */
     615                 : /*      Try adding the SRS to the SRS table.                            */
     616                 : /* -------------------------------------------------------------------- */
     617                 :     osCommand.Printf(
     618                 :              "INSERT INTO spatial_ref_sys (srid,srtext) VALUES (%d,'%s')",
     619               1 :              nSRSId, pszWKT );
     620                 : 
     621               1 :     if( !mysql_query( GetConn(), osCommand ) )
     622               1 :         hResult = mysql_store_result( GetConn() );
     623                 : 
     624                 :     // make sure to attempt to free results of successful queries
     625               1 :     hResult = mysql_store_result( GetConn() );
     626               1 :     if( hResult != NULL )
     627               0 :         mysql_free_result( hResult );
     628               1 :     hResult = NULL;
     629                 : 
     630               1 :     CPLFree(pszWKT);
     631                 : 
     632               1 :     return nSRSId;
     633                 : }
     634                 : 
     635                 : /************************************************************************/
     636                 : /*                             ExecuteSQL()                             */
     637                 : /************************************************************************/
     638                 : 
     639              10 : OGRLayer * OGRMySQLDataSource::ExecuteSQL( const char *pszSQLCommand,
     640                 :                                         OGRGeometry *poSpatialFilter,
     641                 :                                         const char *pszDialect )
     642                 : 
     643                 : {
     644              10 :     if( poSpatialFilter != NULL )
     645                 :     {
     646                 :         CPLDebug( "OGR_MYSQL", 
     647               0 :           "Spatial filter ignored for now in OGRMySQLDataSource::ExecuteSQL()" );
     648                 :     }
     649                 : 
     650                 : /* -------------------------------------------------------------------- */
     651                 : /*      Use generic implementation for OGRSQL dialect.                  */
     652                 : /* -------------------------------------------------------------------- */
     653              10 :     if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
     654                 :         return OGRDataSource::ExecuteSQL( pszSQLCommand, 
     655                 :                                           poSpatialFilter, 
     656               0 :                                           pszDialect );
     657                 : 
     658                 : /* -------------------------------------------------------------------- */
     659                 : /*      Special case DELLAYER: command.                                 */
     660                 : /* -------------------------------------------------------------------- */
     661                 : #ifdef notdef
     662                 :     if( EQUALN(pszSQLCommand,"DELLAYER:",9) )
     663                 :     {
     664                 :         const char *pszLayerName = pszSQLCommand + 9;
     665                 : 
     666                 :         while( *pszLayerName == ' ' )
     667                 :             pszLayerName++;
     668                 : 
     669                 :         DeleteLayer( pszLayerName );
     670                 :         return NULL;
     671                 :     }
     672                 : #endif
     673                 : 
     674                 : /* -------------------------------------------------------------------- */
     675                 : /*      Make sure there isn't an active transaction already.            */
     676                 : /* -------------------------------------------------------------------- */
     677              10 :     InterruptLongResult();
     678                 : 
     679                 : /* -------------------------------------------------------------------- */
     680                 : /*      Execute the statement.                                          */
     681                 : /* -------------------------------------------------------------------- */
     682                 :     MYSQL_RES *hResultSet;
     683                 : 
     684              10 :     if( mysql_query( hConn, pszSQLCommand ) )
     685                 :     {
     686               0 :         ReportError( pszSQLCommand );
     687               0 :         return NULL;
     688                 :     }
     689                 : 
     690              10 :     hResultSet = mysql_use_result( hConn );
     691              10 :     if( hResultSet == NULL )
     692                 :     {
     693               6 :         if( mysql_field_count( hConn ) == 0 )
     694                 :         {
     695                 :             CPLDebug( "MYSQL", "Command '%s' succeeded, %d rows affected.", 
     696                 :                       pszSQLCommand, 
     697               6 :                       (int) mysql_affected_rows(hConn) );
     698               6 :             return NULL;
     699                 :         }
     700                 :         else
     701                 :         {
     702               0 :             ReportError( pszSQLCommand );
     703               0 :             return NULL;
     704                 :         }
     705                 :     }
     706                 : 
     707                 : /* -------------------------------------------------------------------- */
     708                 : /*      Do we have a tuple result? If so, instantiate a results         */
     709                 : /*      layer for it.                                                   */
     710                 : /* -------------------------------------------------------------------- */
     711                 : 
     712               4 :     OGRMySQLResultLayer *poLayer = NULL;
     713                 : 
     714               4 :     poLayer = new OGRMySQLResultLayer( this, pszSQLCommand, hResultSet );
     715                 :         
     716               4 :     return poLayer;
     717                 : }
     718                 : 
     719                 : /************************************************************************/
     720                 : /*                          ReleaseResultSet()                          */
     721                 : /************************************************************************/
     722                 : 
     723               4 : void OGRMySQLDataSource::ReleaseResultSet( OGRLayer * poLayer )
     724                 : 
     725                 : {
     726               4 :     delete poLayer;
     727               4 : }
     728                 : 
     729                 : /************************************************************************/
     730                 : /*                            LaunderName()                             */
     731                 : /************************************************************************/
     732                 : 
     733              12 : char *OGRMySQLDataSource::LaunderName( const char *pszSrcName )
     734                 : 
     735                 : {
     736              12 :     char    *pszSafeName = CPLStrdup( pszSrcName );
     737                 :     int     i;
     738                 : 
     739             112 :     for( i = 0; pszSafeName[i] != '\0'; i++ )
     740                 :     {
     741             100 :         pszSafeName[i] = (char) tolower( pszSafeName[i] );
     742             100 :         if( pszSafeName[i] == '-' || pszSafeName[i] == '#' )
     743               0 :             pszSafeName[i] = '_';
     744                 :     }
     745                 : 
     746              12 :     return pszSafeName;
     747                 : }
     748                 : 
     749                 : /************************************************************************/
     750                 : /*                         RequestLongResult()                          */
     751                 : /*                                                                      */
     752                 : /*      Layers need to use mysql_use_result() instead of                */
     753                 : /*      mysql_store_result() so that we won't have to load entire       */
     754                 : /*      result sets into RAM.  But only one "streamed" resultset can    */
     755                 : /*      be active on a database connection at a time.  So we need to    */
     756                 : /*      maintain a way of closing off an active streaming resultset     */
     757                 : /*      before any other sort of query with a resultset is              */
     758                 : /*      executable.  This method (and InterruptLongResult())            */
     759                 : /*      implement that exclusion.                                       */
     760                 : /************************************************************************/
     761                 : 
     762              24 : void OGRMySQLDataSource::RequestLongResult( OGRMySQLLayer * poNewLayer )
     763                 : 
     764                 : {
     765              24 :     InterruptLongResult();
     766              24 :     poLongResultLayer = poNewLayer;
     767              24 : }
     768                 : 
     769                 : /************************************************************************/
     770                 : /*                        InterruptLongResult()                         */
     771                 : /************************************************************************/
     772                 : 
     773             284 : void OGRMySQLDataSource::InterruptLongResult()
     774                 : 
     775                 : {
     776             284 :     if( poLongResultLayer != NULL )
     777                 :     {
     778              27 :         poLongResultLayer->ResetReading();
     779              27 :         poLongResultLayer = NULL;
     780                 :     }
     781             284 : }
     782                 : 
     783                 : 
     784                 : /************************************************************************/
     785                 : /*                            DeleteLayer()                             */
     786                 : /************************************************************************/
     787                 : 
     788               0 : int OGRMySQLDataSource::DeleteLayer( int iLayer)
     789                 : 
     790                 : {
     791               0 :     if( iLayer < 0 || iLayer >= nLayers )
     792               0 :         return OGRERR_FAILURE;
     793                 :         
     794                 : /* -------------------------------------------------------------------- */
     795                 : /*      Blow away our OGR structures related to the layer.  This is     */
     796                 : /*      pretty dangerous if anything has a reference to this layer!     */
     797                 : /* -------------------------------------------------------------------- */
     798               0 :     CPLString osLayerName = papoLayers[iLayer]->GetLayerDefn()->GetName();
     799                 :     
     800               0 :     CPLDebug( "MYSQL", "DeleteLayer(%s)", osLayerName.c_str() );
     801                 : 
     802               0 :     delete papoLayers[iLayer];
     803                 :     memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
     804               0 :              sizeof(void *) * (nLayers - iLayer - 1) );
     805               0 :     nLayers--;
     806                 : 
     807                 : /* -------------------------------------------------------------------- */
     808                 : /*      Remove from the database.                                       */
     809                 : /* -------------------------------------------------------------------- */
     810               0 :     CPLString osCommand;
     811                 : 
     812                 :     osCommand.Printf(
     813                 :              "DROP TABLE `%s` ",
     814               0 :              osLayerName.c_str() );
     815                 : 
     816               0 :     if( !mysql_query(GetConn(), osCommand ) )
     817                 :     {
     818               0 :         CPLDebug("MYSQL","Dropped table %s.", osLayerName.c_str());
     819               0 :         return OGRERR_NONE;
     820                 :     }
     821                 :     else
     822                 :     {
     823               0 :         ReportError( osCommand );
     824               0 :         return OGRERR_FAILURE;
     825               0 :     }
     826                 : 
     827                 : }
     828                 : 
     829                 : /************************************************************************/
     830                 : /*                            CreateLayer()                             */
     831                 : /************************************************************************/
     832                 : 
     833                 : OGRLayer *
     834               4 : OGRMySQLDataSource::CreateLayer( const char * pszLayerNameIn,
     835                 :                               OGRSpatialReference *poSRS,
     836                 :                               OGRwkbGeometryType eType,
     837                 :                               char ** papszOptions )
     838                 : 
     839                 : {
     840               4 :     MYSQL_RES           *hResult=NULL;
     841               4 :     CPLString            osCommand;
     842                 :     const char          *pszGeometryType;
     843                 :     const char      *pszGeomColumnName;
     844                 :     const char      *pszExpectedFIDName; 
     845                 :   
     846                 :     char                *pszLayerName;
     847               4 :     int                 nDimension = 3; // MySQL only supports 2d currently
     848                 : 
     849                 : 
     850                 : /* -------------------------------------------------------------------- */
     851                 : /*      Make sure there isn't an active transaction already.            */
     852                 : /* -------------------------------------------------------------------- */
     853               4 :     InterruptLongResult();
     854                 : 
     855                 : 
     856               4 :     if( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) )
     857               4 :         pszLayerName = LaunderName( pszLayerNameIn );
     858                 :     else
     859               0 :         pszLayerName = CPLStrdup( pszLayerNameIn );
     860                 : 
     861               4 :     if( wkbFlatten(eType) == eType )
     862               4 :         nDimension = 2;
     863                 : 
     864               4 :     CPLDebug("MYSQL","Creating layer %s.", pszLayerName);
     865                 : 
     866                 : /* -------------------------------------------------------------------- */
     867                 : /*      Do we already have this layer?  If so, should we blow it        */
     868                 : /*      away?                                                           */
     869                 : /* -------------------------------------------------------------------- */
     870                 : 
     871                 :     int iLayer;
     872              50 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
     873                 :     {
     874              46 :         if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
     875                 :         {
     876                 :       
     877               0 :             if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
     878                 :                 && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
     879                 :             {
     880               0 :                 DeleteLayer( iLayer );
     881                 :             }
     882                 :             else
     883                 :             {
     884                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     885                 :                           "Layer %s already exists, CreateLayer failed.\n"
     886                 :                           "Use the layer creation option OVERWRITE=YES to "
     887                 :                           "replace it.",
     888               0 :                           pszLayerName );
     889               0 :                 CPLFree( pszLayerName );
     890               0 :                 return NULL;
     891                 :             }
     892                 :         }
     893                 :     }
     894                 : 
     895               4 :     pszGeomColumnName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME" );
     896               4 :     if (!pszGeomColumnName)
     897               4 :         pszGeomColumnName="SHAPE";
     898                 : 
     899               4 :     pszExpectedFIDName = CSLFetchNameValue( papszOptions, "MYSQL_FID" );
     900               4 :     if (!pszExpectedFIDName)
     901               4 :         pszExpectedFIDName="OGR_FID";
     902                 : 
     903                 : 
     904               4 :     CPLDebug("MYSQL","Geometry Column Name %s.", pszGeomColumnName);
     905               4 :     CPLDebug("MYSQL","FID Column Name %s.", pszExpectedFIDName);
     906                 : 
     907               4 :     if( wkbFlatten(eType) == wkbNone )
     908                 :     {
     909                 :         osCommand.Printf(
     910                 :                  "CREATE TABLE `%s` ( "
     911                 :                  "   %s INT UNIQUE NOT NULL AUTO_INCREMENT )",
     912               0 :                  pszLayerName, pszExpectedFIDName );
     913                 :     }
     914                 :     else
     915                 :     {
     916                 :         osCommand.Printf(
     917                 :                  "CREATE TABLE `%s` ( "
     918                 :                  "   %s INT UNIQUE NOT NULL AUTO_INCREMENT, "
     919                 :                  "   %s GEOMETRY NOT NULL )",
     920               4 :                  pszLayerName, pszExpectedFIDName, pszGeomColumnName );
     921                 :     }
     922                 : 
     923               4 :     if( CSLFetchNameValue( papszOptions, "ENGINE" ) != NULL )
     924                 :     {
     925               4 :         osCommand += " ENGINE = ";
     926               4 :         osCommand += CSLFetchNameValue( papszOptions, "ENGINE" );
     927                 :     }
     928                 :   
     929               4 :     if( !mysql_query(GetConn(), osCommand ) )
     930                 :     {
     931               4 :         if( mysql_field_count( GetConn() ) == 0 )
     932               4 :             CPLDebug("MYSQL","Created table %s.", pszLayerName);
     933                 :         else
     934                 :         {
     935               0 :             ReportError( osCommand );
     936               0 :             return NULL;
     937                 :         }
     938                 :     }
     939                 :     else
     940                 :     {
     941               0 :         ReportError( osCommand );
     942               0 :         return NULL;
     943                 :     }
     944                 : 
     945                 :     // make sure to attempt to free results of successful queries
     946               8 :     hResult = mysql_store_result( GetConn() );
     947               4 :     if( hResult != NULL )
     948               0 :         mysql_free_result( hResult );
     949               4 :     hResult = NULL;
     950                 :     
     951                 :     // Calling this does no harm
     952               4 :     InitializeMetadataTables();
     953                 :     
     954                 : /* -------------------------------------------------------------------- */
     955                 : /*      Try to get the SRS Id of this spatial reference system,         */
     956                 : /*      adding tot the srs table if needed.                             */
     957                 : /* -------------------------------------------------------------------- */
     958               4 :     int nSRSId = -1;
     959                 : 
     960               4 :     if( poSRS != NULL )
     961               1 :         nSRSId = FetchSRSId( poSRS );
     962                 : 
     963                 : /* -------------------------------------------------------------------- */
     964                 : /*      Sometimes there is an old crufty entry in the geometry_columns  */
     965                 : /*      table if things were not properly cleaned up before.  We make   */
     966                 : /*      an effort to clean out such cruft.                              */
     967                 : /*                                                                      */
     968                 : /* -------------------------------------------------------------------- */
     969                 :     osCommand.Printf(
     970                 :              "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
     971               4 :              pszLayerName );
     972                 : 
     973               4 :     if( mysql_query(GetConn(), osCommand ) )
     974                 :     {
     975               0 :         ReportError( osCommand );
     976               0 :         return NULL;
     977                 :     }
     978                 : 
     979                 :     // make sure to attempt to free results of successful queries
     980               4 :     hResult = mysql_store_result( GetConn() );
     981               4 :     if( hResult != NULL )
     982               0 :         mysql_free_result( hResult );
     983               4 :     hResult = NULL;   
     984                 :         
     985                 : /* -------------------------------------------------------------------- */
     986                 : /*      Attempt to add this table to the geometry_columns table, if     */
     987                 : /*      it is a spatial layer.                                          */
     988                 : /* -------------------------------------------------------------------- */
     989               4 :     if( eType != wkbNone )
     990                 :     {
     991                 :         int nCoordDimension;
     992               4 :         if( eType == wkbFlatten(eType) )
     993               4 :             nCoordDimension = 2;
     994                 :         else
     995               0 :             nCoordDimension = 3;
     996                 : 
     997               4 :         pszGeometryType = OGRToOGCGeomType(eType);
     998                 : 
     999               4 :         if( nSRSId == -1 )
    1000                 :             osCommand.Printf(
    1001                 :                      "INSERT INTO geometry_columns "
    1002                 :                      " (F_TABLE_NAME, "
    1003                 :                      "  F_GEOMETRY_COLUMN, "
    1004                 :                      "  COORD_DIMENSION, "
    1005                 :                      "  TYPE) values "
    1006                 :                      "  ('%s', '%s', %d, '%s')",
    1007                 :                      pszLayerName,
    1008                 :                      pszGeomColumnName,
    1009                 :                      nCoordDimension,
    1010               3 :                      pszGeometryType );
    1011                 :         else
    1012                 :             osCommand.Printf(
    1013                 :                      "INSERT INTO geometry_columns "
    1014                 :                      " (F_TABLE_NAME, "
    1015                 :                      "  F_GEOMETRY_COLUMN, "
    1016                 :                      "  COORD_DIMENSION, "
    1017                 :                      "  SRID, "
    1018                 :                      "  TYPE) values "
    1019                 :                      "  ('%s', '%s', %d, %d, '%s')",
    1020                 :                      pszLayerName,
    1021                 :                      pszGeomColumnName,
    1022                 :                      nCoordDimension,
    1023                 :                      nSRSId,
    1024               1 :                      pszGeometryType );
    1025                 : 
    1026               4 :         if( mysql_query(GetConn(), osCommand ) )
    1027                 :         {
    1028               0 :             ReportError( osCommand );
    1029               0 :             return NULL;
    1030                 :         }
    1031                 : 
    1032                 :         // make sure to attempt to free results of successful queries
    1033               4 :         hResult = mysql_store_result( GetConn() );
    1034               4 :         if( hResult != NULL )
    1035               0 :             mysql_free_result( hResult );
    1036               4 :         hResult = NULL;   
    1037                 :     }
    1038                 : 
    1039                 : /* -------------------------------------------------------------------- */
    1040                 : /*      Create the spatial index.                                       */
    1041                 : /*                                                                      */
    1042                 : /*      We're doing this before we add geometry and record to the table */
    1043                 : /*      so this may not be exactly the best way to do it.               */
    1044                 : /* -------------------------------------------------------------------- */
    1045               4 :     const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
    1046                 : 
    1047               4 :     if( eType != wkbNone && (pszSI == NULL || CSLTestBoolean(pszSI)) )
    1048                 :     {
    1049                 :         osCommand.Printf(
    1050                 :                  "ALTER TABLE `%s` ADD SPATIAL INDEX(`%s`) ",
    1051                 :                  pszLayerName,
    1052               3 :                  pszGeomColumnName);
    1053                 : 
    1054               3 :         if( mysql_query(GetConn(), osCommand ) )
    1055                 :         {
    1056               0 :             ReportError( osCommand );
    1057               0 :             return NULL;
    1058                 :         }
    1059                 : 
    1060                 :         // make sure to attempt to free results of successful queries
    1061               3 :         hResult = mysql_store_result( GetConn() );
    1062               3 :         if( hResult != NULL )
    1063               0 :             mysql_free_result( hResult );
    1064               3 :         hResult = NULL;   
    1065                 :     }
    1066                 :         
    1067                 : /* -------------------------------------------------------------------- */
    1068                 : /*      Create the layer object.                                        */
    1069                 : /* -------------------------------------------------------------------- */
    1070                 :     OGRMySQLTableLayer     *poLayer;
    1071                 :     OGRErr                  eErr;
    1072                 : 
    1073               4 :     poLayer = new OGRMySQLTableLayer( this, pszLayerName, TRUE, nSRSId );
    1074               8 :     eErr = poLayer->Initialize(pszLayerName);
    1075               4 :     if (eErr == OGRERR_FAILURE)
    1076               0 :         return NULL;
    1077                 : 
    1078               4 :     poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
    1079               4 :     poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
    1080                 : 
    1081                 : /* -------------------------------------------------------------------- */
    1082                 : /*      Add layer to data source layer list.                            */
    1083                 : /* -------------------------------------------------------------------- */
    1084                 :     papoLayers = (OGRMySQLLayer **)
    1085               4 :         CPLRealloc( papoLayers,  sizeof(OGRMySQLLayer *) * (nLayers+1) );
    1086                 : 
    1087               4 :     papoLayers[nLayers++] = poLayer;
    1088                 : 
    1089               4 :     CPLFree( pszLayerName );
    1090                 : 
    1091               4 :     return poLayer;
    1092                 : }

Generated by: LCOV version 1.7