LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mysql - ogrmysqldatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 382 273 71.5 %
Date: 2012-04-28 Functions: 20 15 75.0 %

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

Generated by: LCOV version 1.7