LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mysql - ogrmysqldatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 418 507 82.4 %
Date: 2024-11-21 22:18:42 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRMySQLDataSource class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  * Author:   Howard Butler, hobu@hobu.net
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
      10             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include <string>
      16             : #include "ogr_mysql.h"
      17             : 
      18             : #include "cpl_conv.h"
      19             : #include "cpl_string.h"
      20             : 
      21             : /************************************************************************/
      22             : /*                       FreeResultAndNullify()                         */
      23             : /************************************************************************/
      24             : 
      25        1006 : inline void FreeResultAndNullify(MYSQL_RES *&hResult)
      26             : {
      27        1006 :     if (hResult)
      28             :     {
      29         388 :         mysql_free_result(hResult);
      30         388 :         hResult = nullptr;
      31             :     }
      32        1006 : }
      33             : 
      34             : /************************************************************************/
      35             : /*                         OGRMySQLDataSource()                         */
      36             : /************************************************************************/
      37             : 
      38          63 : OGRMySQLDataSource::OGRMySQLDataSource()
      39             :     : papoLayers(nullptr), nLayers(0), bDSUpdate(FALSE), hConn(nullptr),
      40          63 :       poLongResultLayer(nullptr)
      41             : {
      42          63 : }
      43             : 
      44             : /************************************************************************/
      45             : /*                        ~OGRMySQLDataSource()                         */
      46             : /************************************************************************/
      47             : 
      48         126 : OGRMySQLDataSource::~OGRMySQLDataSource()
      49             : 
      50             : {
      51          63 :     InterruptLongResult();
      52             : 
      53         249 :     for (int i = 0; i < nLayers; i++)
      54         186 :         delete papoLayers[i];
      55             : 
      56          63 :     CPLFree(papoLayers);
      57             : 
      58          63 :     if (hConn != nullptr)
      59          62 :         mysql_close(hConn);
      60         126 : }
      61             : 
      62             : /************************************************************************/
      63             : /*                          GetUnknownSRID()                            */
      64             : /************************************************************************/
      65             : 
      66         352 : int OGRMySQLDataSource::GetUnknownSRID() const
      67             : {
      68         352 :     return m_nMajor >= 8 && !m_bIsMariaDB ? 0 : -1;
      69             : }
      70             : 
      71             : /************************************************************************/
      72             : /*                            ReportError()                             */
      73             : /************************************************************************/
      74             : 
      75          10 : void OGRMySQLDataSource::ReportError(const char *pszDescription)
      76             : 
      77             : {
      78          10 :     if (pszDescription)
      79          10 :         CPLError(CE_Failure, CPLE_AppDefined,
      80             :                  "MySQL error message:%s Description: %s", mysql_error(hConn),
      81             :                  pszDescription);
      82             :     else
      83           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", mysql_error(hConn));
      84          10 : }
      85             : 
      86             : /************************************************************************/
      87             : /*                                Open()                                */
      88             : /************************************************************************/
      89             : 
      90          63 : int OGRMySQLDataSource::Open(const char *pszNewName, char **papszOpenOptionsIn,
      91             :                              int bUpdate)
      92             : 
      93             : {
      94          63 :     CPLAssert(nLayers == 0);
      95             : 
      96             :     /* -------------------------------------------------------------------- */
      97             :     /*      Use options process to get .my.cnf file contents.               */
      98             :     /* -------------------------------------------------------------------- */
      99          63 :     int nPort = 0;
     100          63 :     char **papszTableNames = nullptr;
     101         126 :     std::string oHost, oPassword, oUser, oDB;
     102             : 
     103         126 :     CPLString osNewName(pszNewName);
     104          63 :     const char *apszOpenOptions[] = {"dbname",   "port", "user",
     105             :                                      "password", "host", "tables"};
     106         441 :     for (int i = 0; i < (int)(sizeof(apszOpenOptions) / sizeof(char *)); i++)
     107             :     {
     108             :         const char *pszVal =
     109         378 :             CSLFetchNameValue(papszOpenOptionsIn, apszOpenOptions[i]);
     110         378 :         if (pszVal)
     111             :         {
     112           0 :             if (osNewName.back() != ':')
     113           0 :                 osNewName += ",";
     114           0 :             if (i > 0)
     115             :             {
     116           0 :                 osNewName += apszOpenOptions[i];
     117           0 :                 osNewName += "=";
     118             :             }
     119           0 :             if (EQUAL(apszOpenOptions[i], "tables"))
     120             :             {
     121           0 :                 for (; *pszVal; ++pszVal)
     122             :                 {
     123           0 :                     if (*pszVal == ',')
     124           0 :                         osNewName += ";";
     125             :                     else
     126           0 :                         osNewName += *pszVal;
     127             :                 }
     128             :             }
     129             :             else
     130           0 :                 osNewName += pszVal;
     131             :         }
     132             :     }
     133             : 
     134             :     /* -------------------------------------------------------------------- */
     135             :     /*      Parse out connection information.                               */
     136             :     /* -------------------------------------------------------------------- */
     137             :     char **papszItems =
     138          63 :         CSLTokenizeString2(osNewName + 6, ",", CSLT_HONOURSTRINGS);
     139             : 
     140          63 :     if (CSLCount(papszItems) < 1)
     141             :     {
     142           0 :         CSLDestroy(papszItems);
     143           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     144             :                  "MYSQL: request missing databasename.");
     145           0 :         return FALSE;
     146             :     }
     147             : 
     148          63 :     oDB = papszItems[0];
     149             : 
     150         311 :     for (int i = 1; papszItems[i] != nullptr; i++)
     151             :     {
     152         248 :         if (STARTS_WITH_CI(papszItems[i], "user="))
     153          62 :             oUser = papszItems[i] + 5;
     154         186 :         else if (STARTS_WITH_CI(papszItems[i], "password="))
     155          62 :             oPassword = papszItems[i] + 9;
     156         124 :         else if (STARTS_WITH_CI(papszItems[i], "host="))
     157          62 :             oHost = papszItems[i] + 5;
     158          62 :         else if (STARTS_WITH_CI(papszItems[i], "port="))
     159          62 :             nPort = atoi(papszItems[i] + 5);
     160           0 :         else if (STARTS_WITH_CI(papszItems[i], "tables="))
     161             :         {
     162           0 :             CSLDestroy(papszTableNames);
     163             :             papszTableNames =
     164           0 :                 CSLTokenizeStringComplex(papszItems[i] + 7, ";", FALSE, FALSE);
     165             :         }
     166             :         else
     167           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     168             :                      "'%s' in MYSQL datasource definition not recognised and "
     169             :                      "ignored.",
     170           0 :                      papszItems[i]);
     171             :     }
     172             : 
     173          63 :     CSLDestroy(papszItems);
     174             : 
     175             :     /* -------------------------------------------------------------------- */
     176             :     /*      Try to establish connection.                                    */
     177             :     /* -------------------------------------------------------------------- */
     178          63 :     hConn = mysql_init(nullptr);
     179             : 
     180          63 :     if (hConn == nullptr)
     181             :     {
     182           0 :         CPLError(CE_Failure, CPLE_AppDefined, "mysql_init() failed.");
     183             :     }
     184             : 
     185             :     /* -------------------------------------------------------------------- */
     186             :     /*      Set desired options on the connection: charset and timeout.     */
     187             :     /* -------------------------------------------------------------------- */
     188          63 :     if (hConn)
     189             :     {
     190          63 :         const char *pszTimeoutLength = CPLGetConfigOption("MYSQL_TIMEOUT", "0");
     191             : 
     192          63 :         unsigned int timeout = atoi(pszTimeoutLength);
     193          63 :         mysql_options(hConn, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&timeout);
     194             : 
     195          63 :         mysql_options(hConn, MYSQL_SET_CHARSET_NAME, "utf8");
     196             :     }
     197             : 
     198             :     /* -------------------------------------------------------------------- */
     199             :     /*      Perform connection.                                             */
     200             :     /* -------------------------------------------------------------------- */
     201         126 :     if (hConn &&
     202         251 :         mysql_real_connect(hConn, oHost.length() ? oHost.c_str() : nullptr,
     203         125 :                            oUser.length() ? oUser.c_str() : nullptr,
     204         125 :                            oPassword.length() ? oPassword.c_str() : nullptr,
     205         126 :                            oDB.length() ? oDB.c_str() : nullptr, nPort, nullptr,
     206             :                            CLIENT_INTERACTIVE) == nullptr)
     207             :     {
     208           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     209             :                  "MySQL connect failed for: %s\n%s", pszNewName + 6,
     210             :                  mysql_error(hConn));
     211           1 :         mysql_close(hConn);
     212           1 :         hConn = nullptr;
     213             :     }
     214             : 
     215          63 :     if (hConn == nullptr)
     216             :     {
     217           1 :         CSLDestroy(papszTableNames);
     218           1 :         return FALSE;
     219             :     }
     220             :     else
     221             :     {
     222             :         // Enable automatic reconnection
     223             : #if defined(LIBMYSQL_VERSION_ID) && (LIBMYSQL_VERSION_ID >= 80000)
     224          62 :         bool reconnect = 1;
     225             : #else
     226             :         my_bool reconnect = 1;
     227             : #endif
     228             :         // Must be called after mysql_real_connect() on MySQL < 5.0.19
     229             :         // and at any point on more recent versions.
     230          62 :         mysql_options(hConn, MYSQL_OPT_RECONNECT, &reconnect);
     231             :     }
     232             : 
     233          62 :     bDSUpdate = bUpdate;
     234             : 
     235             :     /* -------------------------------------------------------------------- */
     236             :     /*      Check version.                                                  */
     237             :     /* -------------------------------------------------------------------- */
     238          62 :     auto versionLyr = ExecuteSQL("SELECT VERSION()", nullptr, nullptr);
     239          62 :     if (versionLyr)
     240             :     {
     241          62 :         auto versionFeat = versionLyr->GetNextFeature();
     242          62 :         if (versionFeat)
     243             :         {
     244          62 :             const char *pszVersion = versionFeat->GetFieldAsString(0);
     245          62 :             m_nMajor = atoi(pszVersion);
     246          62 :             const char *pszDot = strchr(pszVersion, '.');
     247          62 :             if (pszDot)
     248          62 :                 m_nMinor = atoi(pszDot + 1);
     249          62 :             m_bIsMariaDB = strstr(pszVersion, "MariaDB") != nullptr;
     250             :         }
     251          62 :         delete versionFeat;
     252          62 :         ReleaseResultSet(versionLyr);
     253             :     }
     254             : 
     255             :     /* -------------------------------------------------------------------- */
     256             :     /*      Get a list of available tables.                                 */
     257             :     /* -------------------------------------------------------------------- */
     258          62 :     if (papszTableNames == nullptr)
     259             :     {
     260             :         MYSQL_RES *hResultSet;
     261             :         MYSQL_ROW papszRow;
     262             : 
     263          62 :         if (mysql_query(hConn, "SHOW TABLES"))
     264             :         {
     265           0 :             ReportError("SHOW TABLES Failed");
     266           0 :             return FALSE;
     267             :         }
     268             : 
     269          62 :         hResultSet = mysql_store_result(hConn);
     270          62 :         if (hResultSet == nullptr)
     271             :         {
     272           0 :             ReportError("mysql_store_result() failed on SHOW TABLES result.");
     273           0 :             return FALSE;
     274             :         }
     275             : 
     276          84 :         while ((papszRow = mysql_fetch_row(hResultSet)) != nullptr)
     277             :         {
     278          22 :             if (papszRow[0] == nullptr)
     279           0 :                 continue;
     280             : 
     281          22 :             if (EQUAL(papszRow[0], "spatial_ref_sys") ||
     282          17 :                 EQUAL(papszRow[0], "geometry_columns"))
     283          10 :                 continue;
     284             : 
     285          12 :             papszTableNames = CSLAddString(papszTableNames, papszRow[0]);
     286             :         }
     287             : 
     288          62 :         FreeResultAndNullify(hResultSet);
     289             :     }
     290             : 
     291             :     /* -------------------------------------------------------------------- */
     292             :     /*      Get the schema of the available tables.                         */
     293             :     /* -------------------------------------------------------------------- */
     294          74 :     for (int iRecord = 0;
     295          74 :          papszTableNames != nullptr && papszTableNames[iRecord] != nullptr;
     296             :          iRecord++)
     297             :     {
     298             :         //  FIXME: This should be fixed to deal with tables
     299             :         //  for which we can't open because the name is bad/
     300          12 :         OpenTable(papszTableNames[iRecord], bUpdate);
     301             :     }
     302             : 
     303          62 :     CSLDestroy(papszTableNames);
     304             : 
     305          62 :     return nLayers > 0 || bUpdate;
     306             : }
     307             : 
     308             : /************************************************************************/
     309             : /*                             OpenTable()                              */
     310             : /************************************************************************/
     311             : 
     312          12 : int OGRMySQLDataSource::OpenTable(const char *pszNewName, int bUpdate)
     313             : 
     314             : {
     315             :     /* -------------------------------------------------------------------- */
     316             :     /*      Create the layer object.                                        */
     317             :     /* -------------------------------------------------------------------- */
     318             :     OGRMySQLTableLayer *poLayer;
     319             :     OGRErr eErr;
     320             : 
     321          12 :     poLayer = new OGRMySQLTableLayer(this, pszNewName, bUpdate);
     322          12 :     eErr = poLayer->Initialize(pszNewName);
     323          12 :     if (eErr == OGRERR_FAILURE)
     324           0 :         return FALSE;
     325             : 
     326             :     /* -------------------------------------------------------------------- */
     327             :     /*      Add layer to data source layer list.                            */
     328             :     /* -------------------------------------------------------------------- */
     329          24 :     papoLayers = (OGRMySQLLayer **)CPLRealloc(
     330          12 :         papoLayers, sizeof(OGRMySQLLayer *) * (nLayers + 1));
     331          12 :     papoLayers[nLayers++] = poLayer;
     332             : 
     333          12 :     return TRUE;
     334             : }
     335             : 
     336             : /************************************************************************/
     337             : /*                           TestCapability()                           */
     338             : /************************************************************************/
     339             : 
     340          38 : int OGRMySQLDataSource::TestCapability(const char *pszCap)
     341             : 
     342             : {
     343          38 :     if (EQUAL(pszCap, ODsCCreateLayer))
     344           4 :         return TRUE;
     345          34 :     if (EQUAL(pszCap, ODsCDeleteLayer))
     346           2 :         return TRUE;
     347          32 :     if (EQUAL(pszCap, ODsCRandomLayerWrite))
     348           0 :         return TRUE;
     349          32 :     if (EQUAL(pszCap, ODsCMeasuredGeometries))
     350           4 :         return TRUE;
     351          28 :     if (EQUAL(pszCap, ODsCZGeometries))
     352           4 :         return TRUE;
     353             : 
     354          24 :     return FALSE;
     355             : }
     356             : 
     357             : /************************************************************************/
     358             : /*                              GetLayer()                              */
     359             : /************************************************************************/
     360             : 
     361        3985 : OGRLayer *OGRMySQLDataSource::GetLayer(int iLayer)
     362             : 
     363             : {
     364        3985 :     if (iLayer < 0 || iLayer >= nLayers)
     365           4 :         return nullptr;
     366             :     else
     367        3981 :         return papoLayers[iLayer];
     368             : }
     369             : 
     370             : /* =====================================================================*/
     371             : /* Handle spatial reference id and index for older MySQL and MariaDB    */
     372             : /* =====================================================================*/
     373             : 
     374             : /************************************************************************/
     375             : /*                      InitializeMetadataTables()                      */
     376             : /*                                                                      */
     377             : /*      Create the metadata tables (SPATIAL_REF_SYS and                 */
     378             : /*      GEOMETRY_COLUMNS). This method "does no harm" if the tables     */
     379             : /*      exist and can be called at will.                                */
     380             : /************************************************************************/
     381             : 
     382         176 : OGRErr OGRMySQLDataSource::InitializeMetadataTables()
     383             : 
     384             : {
     385             :     const char *pszCommand;
     386             :     MYSQL_RES *hResult;
     387         176 :     OGRErr eErr = OGRERR_NONE;
     388             : 
     389         176 :     if (GetMajorVersion() < 8 || IsMariaDB())
     390             :     {
     391          54 :         pszCommand = "DESCRIBE geometry_columns";
     392          54 :         if (mysql_query(GetConn(), pszCommand))
     393             :         {
     394          23 :             pszCommand = "CREATE TABLE geometry_columns "
     395             :                          "( F_TABLE_CATALOG VARCHAR(256), "
     396             :                          "F_TABLE_SCHEMA VARCHAR(256), "
     397             :                          "F_TABLE_NAME VARCHAR(256) NOT NULL,"
     398             :                          "F_GEOMETRY_COLUMN VARCHAR(256) NOT NULL, "
     399             :                          "COORD_DIMENSION INT, "
     400             :                          "SRID INT,"
     401             :                          "TYPE VARCHAR(256) NOT NULL)";
     402          23 :             if (mysql_query(GetConn(), pszCommand))
     403             :             {
     404           0 :                 ReportError(pszCommand);
     405           0 :                 eErr = OGRERR_FAILURE;
     406             :             }
     407             :             else
     408          23 :                 CPLDebug("MYSQL", "Creating geometry_columns metadata table");
     409             :         }
     410             : 
     411             :         // make sure to attempt to free results of successful queries
     412          54 :         hResult = mysql_store_result(GetConn());
     413          54 :         FreeResultAndNullify(hResult);
     414             : 
     415          54 :         pszCommand = "DESCRIBE spatial_ref_sys";
     416          54 :         if (mysql_query(GetConn(), pszCommand))
     417             :         {
     418          23 :             pszCommand = "CREATE TABLE spatial_ref_sys "
     419             :                          "(SRID INT NOT NULL, "
     420             :                          "AUTH_NAME VARCHAR(256), "
     421             :                          "AUTH_SRID INT, "
     422             :                          "SRTEXT VARCHAR(2048))";
     423          23 :             if (mysql_query(GetConn(), pszCommand))
     424             :             {
     425           0 :                 ReportError(pszCommand);
     426           0 :                 eErr = OGRERR_FAILURE;
     427             :             }
     428             :             else
     429          23 :                 CPLDebug("MYSQL", "Creating spatial_ref_sys metadata table");
     430             :         }
     431             : 
     432             :         // make sure to attempt to free results of successful queries
     433          54 :         hResult = mysql_store_result(GetConn());
     434          54 :         FreeResultAndNullify(hResult);
     435             :     }
     436             : 
     437         176 :     return eErr;
     438             : }
     439             : 
     440         176 : OGRErr OGRMySQLDataSource::UpdateMetadataTables(const char *pszLayerName,
     441             :                                                 OGRwkbGeometryType eType,
     442             :                                                 const char *pszGeomColumnName,
     443             :                                                 const int nSRSId)
     444             : 
     445             : {
     446         176 :     MYSQL_RES *hResult = nullptr;
     447         352 :     CPLString osCommand;
     448             :     const char *pszGeometryType;
     449             : 
     450         176 :     if (GetMajorVersion() < 8 || IsMariaDB())
     451             :     {
     452             :         /* --------------------------------------------------------------------
     453             :          */
     454             :         /*      Sometimes there is an old crufty entry in the geometry_columns
     455             :          */
     456             :         /*      table if things were not properly cleaned up before.  We make */
     457             :         /*      an effort to clean out such cruft. */
     458             :         /*                                                                      */
     459             :         /* --------------------------------------------------------------------
     460             :          */
     461             :         osCommand.Printf(
     462             :             "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
     463          54 :             pszLayerName);
     464             : 
     465          54 :         if (mysql_query(GetConn(), osCommand))
     466             :         {
     467           0 :             ReportError(osCommand);
     468           0 :             return OGRERR_FAILURE;
     469             :         }
     470             : 
     471             :         // make sure to attempt to free results of successful queries
     472          54 :         hResult = mysql_store_result(GetConn());
     473          54 :         FreeResultAndNullify(hResult);
     474             : 
     475             :         /* --------------------------------------------------------------------
     476             :          */
     477             :         /*      Attempt to add this table to the geometry_columns table, if */
     478             :         /*      it is a spatial layer. */
     479             :         /* --------------------------------------------------------------------
     480             :          */
     481          54 :         if (eType != wkbNone)
     482             :         {
     483          52 :             const int nCoordDimension = eType == wkbFlatten(eType) ? 2 : 3;
     484             : 
     485          52 :             pszGeometryType = OGRToOGCGeomType(eType);
     486             : 
     487          52 :             if (nSRSId == GetUnknownSRID())
     488             :                 osCommand.Printf("INSERT INTO geometry_columns "
     489             :                                  " (F_TABLE_NAME, "
     490             :                                  "  F_GEOMETRY_COLUMN, "
     491             :                                  "  COORD_DIMENSION, "
     492             :                                  "  TYPE) values "
     493             :                                  "  ('%s', '%s', %d, '%s')",
     494             :                                  pszLayerName, pszGeomColumnName,
     495           5 :                                  nCoordDimension, pszGeometryType);
     496             :             else
     497             :                 osCommand.Printf("INSERT INTO geometry_columns "
     498             :                                  " (F_TABLE_NAME, "
     499             :                                  "  F_GEOMETRY_COLUMN, "
     500             :                                  "  COORD_DIMENSION, "
     501             :                                  "  SRID, "
     502             :                                  "  TYPE) values "
     503             :                                  "  ('%s', '%s', %d, %d, '%s')",
     504             :                                  pszLayerName, pszGeomColumnName,
     505          47 :                                  nCoordDimension, nSRSId, pszGeometryType);
     506             : 
     507          52 :             if (mysql_query(GetConn(), osCommand))
     508             :             {
     509           0 :                 ReportError(osCommand);
     510           0 :                 return OGRERR_FAILURE;
     511             :             }
     512             : 
     513             :             // make sure to attempt to free results of successful queries
     514          52 :             hResult = mysql_store_result(GetConn());
     515          52 :             FreeResultAndNullify(hResult);
     516             :         }
     517             :     }
     518         176 :     return OGRERR_NONE;
     519             : }
     520             : 
     521             : /* =====================================================================*/
     522             : 
     523             : /************************************************************************/
     524             : /*                              FetchSRS()                              */
     525             : /*                                                                      */
     526             : /*      Return a SRS corresponding to a particular id.  Note that       */
     527             : /*      reference counting should be honoured on the returned           */
     528             : /*      OGRSpatialReference, as handles may be cached.                  */
     529             : /************************************************************************/
     530             : 
     531         172 : const OGRSpatialReference *OGRMySQLDataSource::FetchSRS(int nId)
     532             : {
     533         172 :     if (nId < 0)
     534           0 :         return nullptr;
     535             : 
     536             :     /* -------------------------------------------------------------------- */
     537             :     /*      First, we look through our SRID cache, is it there?             */
     538             :     /* -------------------------------------------------------------------- */
     539         172 :     auto oIter = m_oSRSCache.find(nId);
     540         172 :     if (oIter != m_oSRSCache.end())
     541             :     {
     542         133 :         return oIter->second.get();
     543             :     }
     544             : 
     545             :     // make sure to attempt to free any old results
     546          39 :     MYSQL_RES *hResult = mysql_store_result(GetConn());
     547          39 :     FreeResultAndNullify(hResult);
     548             : 
     549          39 :     char szCommand[128] = {};
     550          39 :     if (GetMajorVersion() < 8 || IsMariaDB())
     551             :     {
     552          18 :         snprintf(szCommand, sizeof(szCommand),
     553             :                  "SELECT srtext FROM spatial_ref_sys WHERE srid = %d", nId);
     554             :     }
     555             :     else
     556             :     {
     557          21 :         snprintf(
     558             :             szCommand, sizeof(szCommand),
     559             :             "SELECT DEFINITION FROM "
     560             :             "INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS WHERE SRS_ID = %d",
     561             :             nId);
     562             :     }
     563             : 
     564          39 :     if (!mysql_query(GetConn(), szCommand))
     565          39 :         hResult = mysql_store_result(GetConn());
     566             : 
     567          39 :     char *pszWKT = nullptr;
     568          39 :     char **papszRow = nullptr;
     569             : 
     570          39 :     if (hResult != nullptr)
     571          39 :         papszRow = mysql_fetch_row(hResult);
     572             : 
     573          39 :     if (papszRow != nullptr && papszRow[0] != nullptr)
     574             :     {
     575          39 :         pszWKT = CPLStrdup(papszRow[0]);
     576             :     }
     577             : 
     578          39 :     FreeResultAndNullify(hResult);
     579             : 
     580             :     std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> poSRS(
     581          78 :         new OGRSpatialReference());
     582          39 :     poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     583          39 :     if (pszWKT == nullptr || poSRS->importFromWkt(pszWKT) != OGRERR_NONE)
     584             :     {
     585           3 :         poSRS.reset();
     586             :     }
     587             : 
     588          39 :     CPLFree(pszWKT);
     589             : 
     590          39 :     if (poSRS)
     591             :     {
     592             :         // The WKT found in MySQL 8 ST_SPATIAL_REFERENCE_SYSTEMS is not
     593             :         // compatible of what GDAL understands.
     594          36 :         const char *pszAuthorityName = poSRS->GetAuthorityName(nullptr);
     595          36 :         const char *pszAuthorityCode = poSRS->GetAuthorityCode(nullptr);
     596          36 :         if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG") &&
     597          34 :             pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
     598             :         {
     599             :             /* Import 'clean' SRS */
     600          34 :             poSRS->importFromEPSG(atoi(pszAuthorityCode));
     601             :         }
     602             :     }
     603             : 
     604             :     /* -------------------------------------------------------------------- */
     605             :     /*      Add to the cache.                                               */
     606             :     /* -------------------------------------------------------------------- */
     607          39 :     oIter = m_oSRSCache.emplace(nId, std::move(poSRS)).first;
     608          39 :     return oIter->second.get();
     609             : }
     610             : 
     611             : /************************************************************************/
     612             : /*                             FetchSRSId()                             */
     613             : /*                                                                      */
     614             : /*      Fetch the id corresponding to an SRS, and if not found, add     */
     615             : /*      it to the table.                                                */
     616             : /************************************************************************/
     617             : 
     618         162 : int OGRMySQLDataSource::FetchSRSId(const OGRSpatialReference *poSRSIn)
     619             : 
     620             : {
     621         162 :     if (poSRSIn == nullptr)
     622           0 :         return GetUnknownSRID();
     623             : 
     624         324 :     OGRSpatialReference oSRS(*poSRSIn);
     625             :     // cppcheck-suppress uselessAssignmentPtrArg
     626         162 :     poSRSIn = nullptr;
     627             : 
     628         162 :     const char *pszAuthorityName = oSRS.GetAuthorityName(nullptr);
     629         162 :     int nAuthorityCode = 0;
     630         162 :     if (pszAuthorityName == nullptr || strlen(pszAuthorityName) == 0)
     631             :     {
     632             :         /* --------------------------------------------------------------------
     633             :          */
     634             :         /*      Try to identify an EPSG code */
     635             :         /* --------------------------------------------------------------------
     636             :          */
     637           4 :         oSRS.AutoIdentifyEPSG();
     638             : 
     639           4 :         pszAuthorityName = oSRS.GetAuthorityName(nullptr);
     640           4 :         if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG"))
     641             :         {
     642           0 :             const char *pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
     643           0 :             if (pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
     644             :             {
     645             :                 /* Import 'clean' SRS */
     646           0 :                 nAuthorityCode = atoi(pszAuthorityCode);
     647           0 :                 oSRS.importFromEPSG(nAuthorityCode);
     648             : 
     649           0 :                 pszAuthorityName = oSRS.GetAuthorityName(nullptr);
     650             :             }
     651           4 :         }
     652             :     }
     653             :     else
     654             :     {
     655         158 :         const char *pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
     656         158 :         if (pszAuthorityCode)
     657         158 :             nAuthorityCode = atoi(pszAuthorityCode);
     658             :     }
     659             : 
     660             :     /* -------------------------------------------------------------------- */
     661             :     /*      Check whether the authority name/code is already mapped to a    */
     662             :     /*      SRS ID.                                                         */
     663             :     /* -------------------------------------------------------------------- */
     664         324 :     CPLString osCommand;
     665         162 :     if (pszAuthorityName != nullptr)
     666             :     {
     667             :         /* Check that the authority code is integral */
     668         158 :         if (nAuthorityCode > 0)
     669             :         {
     670         158 :             const char *pszTableName =
     671             :                 "INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS";
     672         158 :             if (GetMajorVersion() < 8 || IsMariaDB())
     673             :             {
     674          45 :                 pszTableName = "spatial_ref_sys";
     675             :                 osCommand.Printf(
     676             :                     "SELECT srid FROM spatial_ref_sys WHERE "
     677             :                     "auth_name = '%s' AND auth_srid = %d",
     678          90 :                     OGRMySQLEscapeLiteral(pszAuthorityName).c_str(),
     679          45 :                     nAuthorityCode);
     680             :             }
     681             :             else
     682             :             {
     683             :                 osCommand.Printf(
     684             :                     "SELECT SRS_ID FROM "
     685             :                     "INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS "
     686             :                     "WHERE ORGANIZATION = '%s' AND ORGANIZATION_COORDSYS_ID = "
     687             :                     "%d",
     688         226 :                     OGRMySQLEscapeLiteral(pszAuthorityName).c_str(),
     689         113 :                     nAuthorityCode);
     690             :             }
     691             : 
     692         158 :             MYSQL_RES *hResult = nullptr;
     693         158 :             if (!mysql_query(GetConn(), osCommand))
     694         158 :                 hResult = mysql_store_result(GetConn());
     695             : 
     696         158 :             if (hResult != nullptr && !mysql_num_rows(hResult))
     697             :             {
     698          45 :                 CPLDebug("MYSQL",
     699             :                          "No rows exist currently exist in %s for %s:%d",
     700             :                          pszTableName, pszAuthorityName, nAuthorityCode);
     701          45 :                 FreeResultAndNullify(hResult);
     702             :             }
     703         158 :             char **papszRow = nullptr;
     704         158 :             if (hResult != nullptr)
     705         113 :                 papszRow = mysql_fetch_row(hResult);
     706             : 
     707         158 :             if (papszRow != nullptr && papszRow[0] != nullptr)
     708             :             {
     709         113 :                 const int nSRSId = atoi(papszRow[0]);
     710         113 :                 FreeResultAndNullify(hResult);
     711         113 :                 return nSRSId;
     712             :             }
     713             : 
     714             :             // make sure to attempt to free results of successful queries
     715          45 :             hResult = mysql_store_result(GetConn());
     716          45 :             FreeResultAndNullify(hResult);
     717             :         }
     718             :     }
     719             : 
     720             :     /* -------------------------------------------------------------------- */
     721             :     /*      Translate SRS to WKT.                                           */
     722             :     /* -------------------------------------------------------------------- */
     723          49 :     char *pszWKT = nullptr;
     724          49 :     if (oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
     725             :     {
     726           0 :         CPLFree(pszWKT);
     727           0 :         return GetUnknownSRID();
     728             :     }
     729             : 
     730             :     // MySQL 8 requires AXIS[] node in PROJCS.GEOGCS
     731          49 :     if (GetMajorVersion() >= 8 && !IsMariaDB() && oSRS.IsProjected())
     732             :     {
     733           4 :         OGR_SRSNode oNode;
     734           2 :         const char *pszWKTTmp = pszWKT;
     735           2 :         oNode.importFromWkt(&pszWKTTmp);
     736             : 
     737           4 :         OGRSpatialReference oSRSGeog;
     738           2 :         oSRSGeog.CopyGeogCSFrom(&oSRS);
     739           2 :         char *pszWKTGeog = nullptr;
     740           2 :         oSRSGeog.exportToWkt(&pszWKTGeog);
     741             : 
     742           2 :         int iChild = oNode.FindChild("GEOGCS");
     743           2 :         if (iChild >= 0)
     744             :         {
     745           2 :             oNode.DestroyChild(iChild);
     746           2 :             auto poGeogNode = new OGR_SRSNode();
     747           2 :             pszWKTTmp = pszWKTGeog;
     748           2 :             poGeogNode->importFromWkt(&pszWKTTmp);
     749           2 :             oNode.InsertChild(poGeogNode, iChild);
     750             :         }
     751           2 :         CPLFree(pszWKTGeog);
     752             : 
     753           2 :         CPLFree(pszWKT);
     754           2 :         oNode.exportToWkt(&pszWKT);
     755             :     }
     756             : 
     757             :     /* -------------------------------------------------------------------- */
     758             :     /*      Try to find in the existing record.                             */
     759             :     /* -------------------------------------------------------------------- */
     760          49 :     const char *pszTableName =
     761             :         "INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS";
     762          49 :     if (GetMajorVersion() < 8 || IsMariaDB())
     763             :     {
     764          47 :         pszTableName = "spatial_ref_sys";
     765             :         osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE srtext = '%s'",
     766          47 :                          OGRMySQLEscapeLiteral(pszWKT).c_str());
     767             :     }
     768             :     else
     769             :     {
     770             :         osCommand.Printf("SELECT SRS_ID FROM "
     771             :                          "INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS "
     772             :                          "WHERE DEFINITION = '%s'",
     773           2 :                          OGRMySQLEscapeLiteral(pszWKT).c_str());
     774             :     }
     775             : 
     776          49 :     MYSQL_RES *hResult = nullptr;
     777          49 :     if (!mysql_query(GetConn(), osCommand))
     778          49 :         hResult = mysql_store_result(GetConn());
     779             : 
     780          49 :     if (hResult != nullptr && !mysql_num_rows(hResult))
     781             :     {
     782          18 :         CPLDebug("MYSQL", "No rows exist currently exist in %s with WKT = %s",
     783             :                  pszTableName, pszWKT);
     784          18 :         FreeResultAndNullify(hResult);
     785             :     }
     786          49 :     char **papszRow = nullptr;
     787          49 :     if (hResult != nullptr)
     788          31 :         papszRow = mysql_fetch_row(hResult);
     789             : 
     790          49 :     if (papszRow != nullptr && papszRow[0] != nullptr)
     791             :     {
     792          31 :         const int nSRSId = atoi(papszRow[0]);
     793          31 :         FreeResultAndNullify(hResult);
     794          31 :         CPLFree(pszWKT);
     795          31 :         return nSRSId;
     796             :     }
     797             : 
     798             :     // make sure to attempt to free results of successful queries
     799          18 :     hResult = mysql_store_result(GetConn());
     800          18 :     FreeResultAndNullify(hResult);
     801             : 
     802          18 :     if (GetMajorVersion() >= 8 && !IsMariaDB())
     803             :     {
     804           1 :         int nSRSId = -1;
     805           1 :         if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG") &&
     806             :             nAuthorityCode > 0)
     807             :         {
     808             :             /* ------------------------------------------------------------ */
     809             :             /*      If it is an EPSG code, check if we can use the entry of */
     810             :             /*      SRS_ID equal to the EPSG code.                          */
     811             :             /* ------------------------------------------------------------ */
     812             :             osCommand.Printf("SELECT SRS_ID FROM INFORMATION_SCHEMA."
     813             :                              "ST_SPATIAL_REFERENCE_SYSTEMS "
     814             :                              "WHERE SRS_ID = %d",
     815           0 :                              nAuthorityCode);
     816           0 :             if (!mysql_query(GetConn(), osCommand))
     817             :             {
     818           0 :                 hResult = mysql_store_result(GetConn());
     819           0 :                 papszRow = mysql_fetch_row(hResult);
     820           0 :                 if (!(papszRow != nullptr && papszRow[0] != nullptr))
     821             :                 {
     822             :                     // No row matching SRS_ID = nAuthorityCode ? Then
     823             :                     // we can use it
     824           0 :                     nSRSId = nAuthorityCode;
     825             :                 }
     826           0 :                 FreeResultAndNullify(hResult);
     827             :             }
     828             :         }
     829           1 :         if (nSRSId < 0)
     830             :         {
     831           1 :             nSRSId = 1;
     832             : 
     833             :             /* ------------------------------------------------------------- */
     834             :             /*      Get the current maximum srid in the srs table.           */
     835             :             /* ------------------------------------------------------------- */
     836             :             osCommand = "SELECT MAX(SRS_ID) FROM "
     837           1 :                         "INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS";
     838           1 :             if (!mysql_query(GetConn(), osCommand))
     839             :             {
     840           1 :                 hResult = mysql_store_result(GetConn());
     841           1 :                 papszRow = mysql_fetch_row(hResult);
     842           1 :                 if (papszRow != nullptr && papszRow[0] != nullptr)
     843             :                 {
     844           1 :                     nSRSId = atoi(papszRow[0]) + 1;
     845             :                 }
     846           1 :                 FreeResultAndNullify(hResult);
     847             :             }
     848             :         }
     849             :         else
     850             :         {
     851           0 :             nSRSId = nAuthorityCode;
     852             :         }
     853             : 
     854             :         /* ----------------------------------------------------------------- */
     855             :         /*      Check if there's an existing record with same name           */
     856             :         /* ----------------------------------------------------------------- */
     857           1 :         CPLString osName(oSRS.GetName());
     858             : 
     859             :         osCommand.Printf(
     860             :             "SELECT SRS_ID FROM "
     861             :             "INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS WHERE NAME = '%s'",
     862           1 :             osName.c_str());
     863           1 :         if (!mysql_query(GetConn(), osCommand))
     864             :         {
     865           0 :             hResult = mysql_store_result(GetConn());
     866           0 :             papszRow = mysql_fetch_row(hResult);
     867           0 :             if (papszRow != nullptr && papszRow[0] != nullptr)
     868             :             {
     869           0 :                 osName += CPLSPrintf("_srid_%d", nSRSId);
     870             :             }
     871           0 :             FreeResultAndNullify(hResult);
     872             :         }
     873             : 
     874             :         /* ----------------------------------------------------------------- */
     875             :         /*      Try adding the SRS to the SRS table.                         */
     876             :         /* ----------------------------------------------------------------- */
     877           1 :         if (pszAuthorityName != nullptr && nAuthorityCode > 0)
     878             :         {
     879           0 :             osCommand.Printf(
     880             :                 "CREATE SPATIAL REFERENCE SYSTEM %d NAME '%s' "
     881             :                 "ORGANIZATION '%s' "
     882             :                 "IDENTIFIED BY %d "
     883             :                 "DEFINITION '%s'",
     884           0 :                 nSRSId, OGRMySQLEscapeLiteral(osName.c_str()).c_str(),
     885           0 :                 OGRMySQLEscapeLiteral(pszAuthorityName).c_str(), nAuthorityCode,
     886           0 :                 OGRMySQLEscapeLiteral(pszWKT).c_str());
     887             :         }
     888             :         else
     889             :         {
     890             :             osCommand.Printf("CREATE SPATIAL REFERENCE SYSTEM %d NAME '%s' "
     891             :                              "DEFINITION '%s'",
     892             :                              nSRSId,
     893           2 :                              OGRMySQLEscapeLiteral(osName.c_str()).c_str(),
     894           3 :                              OGRMySQLEscapeLiteral(pszWKT).c_str());
     895             :         }
     896             : 
     897           1 :         if (mysql_query(GetConn(), osCommand))
     898             :         {
     899           0 :             ReportError((osCommand + " failed").c_str());
     900           0 :             nSRSId = GetUnknownSRID();
     901             :         }
     902             : 
     903           1 :         hResult = mysql_store_result(GetConn());
     904           1 :         FreeResultAndNullify(hResult);
     905             : 
     906           1 :         CPLFree(pszWKT);
     907           1 :         return nSRSId;
     908             :     }
     909             : 
     910             :     /* -------------------------------------------------------------------- */
     911             :     /*      Get the current maximum srid in the srs table.                  */
     912             :     /* -------------------------------------------------------------------- */
     913          17 :     osCommand = "SELECT MAX(srid) FROM spatial_ref_sys";
     914          17 :     if (!mysql_query(GetConn(), osCommand))
     915             :     {
     916          17 :         hResult = mysql_store_result(GetConn());
     917          17 :         papszRow = mysql_fetch_row(hResult);
     918             :     }
     919             : 
     920          17 :     int nSRSId = papszRow != nullptr && papszRow[0] != nullptr
     921          34 :                      ? atoi(papszRow[0]) + 1
     922             :                      : 1;
     923             : 
     924          17 :     FreeResultAndNullify(hResult);
     925             : 
     926             :     /* -------------------------------------------------------------------- */
     927             :     /*      Try adding the SRS to the SRS table.                            */
     928             :     /* -------------------------------------------------------------------- */
     929          17 :     osCommand.Printf(
     930             :         "INSERT INTO spatial_ref_sys (srid,srtext) VALUES (%d,'%s')", nSRSId,
     931          17 :         pszWKT);
     932             : 
     933          17 :     if (mysql_query(GetConn(), osCommand))
     934             :     {
     935           0 :         ReportError((osCommand + " failed").c_str());
     936           0 :         nSRSId = GetUnknownSRID();
     937             :     }
     938             : 
     939             :     // make sure to attempt to free results of successful queries
     940          17 :     hResult = mysql_store_result(GetConn());
     941          17 :     FreeResultAndNullify(hResult);
     942             : 
     943          17 :     CPLFree(pszWKT);
     944             : 
     945          17 :     return nSRSId;
     946             : }
     947             : 
     948             : /************************************************************************/
     949             : /*                             ExecuteSQL()                             */
     950             : /************************************************************************/
     951             : 
     952         186 : OGRLayer *OGRMySQLDataSource::ExecuteSQL(const char *pszSQLCommand,
     953             :                                          OGRGeometry *poSpatialFilter,
     954             :                                          const char *pszDialect)
     955             : 
     956             : {
     957         186 :     if (poSpatialFilter != nullptr)
     958             :     {
     959           2 :         CPLDebug("OGR_MYSQL", "Spatial filter ignored for now in "
     960             :                               "OGRMySQLDataSource::ExecuteSQL()");
     961             :     }
     962             : 
     963             :     /* -------------------------------------------------------------------- */
     964             :     /*      Use generic implementation for recognized dialects              */
     965             :     /* -------------------------------------------------------------------- */
     966         186 :     if (IsGenericSQLDialect(pszDialect))
     967           0 :         return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter,
     968           0 :                                        pszDialect);
     969             : 
     970             : /* -------------------------------------------------------------------- */
     971             : /*      Special case DELLAYER: command.                                 */
     972             : /* -------------------------------------------------------------------- */
     973             : #ifdef notdef
     974             :     if (STARTS_WITH_CI(pszSQLCommand, "DELLAYER:"))
     975             :     {
     976             :         const char *pszLayerName = pszSQLCommand + 9;
     977             : 
     978             :         while (*pszLayerName == ' ')
     979             :             pszLayerName++;
     980             : 
     981             :         DeleteLayer(pszLayerName);
     982             :         return NULL;
     983             :     }
     984             : #endif
     985             : 
     986             :     /* -------------------------------------------------------------------- */
     987             :     /*      Make sure there isn't an active transaction already.            */
     988             :     /* -------------------------------------------------------------------- */
     989         186 :     InterruptLongResult();
     990             : 
     991             :     /* -------------------------------------------------------------------- */
     992             :     /*      Execute the statement.                                          */
     993             :     /* -------------------------------------------------------------------- */
     994             :     MYSQL_RES *hResultSet;
     995             : 
     996         186 :     if (mysql_query(hConn, pszSQLCommand))
     997             :     {
     998           2 :         ReportError(pszSQLCommand);
     999           2 :         return nullptr;
    1000             :     }
    1001             : 
    1002         184 :     hResultSet = mysql_use_result(hConn);
    1003         184 :     if (hResultSet == nullptr)
    1004             :     {
    1005         100 :         if (mysql_field_count(hConn) == 0)
    1006             :         {
    1007         100 :             CPLDebug("MYSQL", "Command '%s' succeeded, %d rows affected.",
    1008         100 :                      pszSQLCommand, (int)mysql_affected_rows(hConn));
    1009         100 :             return nullptr;
    1010             :         }
    1011             :         else
    1012             :         {
    1013           0 :             ReportError(pszSQLCommand);
    1014           0 :             return nullptr;
    1015             :         }
    1016             :     }
    1017             : 
    1018             :     /* -------------------------------------------------------------------- */
    1019             :     /*      Do we have a tuple result? If so, instantiate a results         */
    1020             :     /*      layer for it.                                                   */
    1021             :     /* -------------------------------------------------------------------- */
    1022             : 
    1023             :     OGRMySQLResultLayer *poLayer =
    1024          84 :         new OGRMySQLResultLayer(this, pszSQLCommand, hResultSet);
    1025             : 
    1026          84 :     return poLayer;
    1027             : }
    1028             : 
    1029             : /************************************************************************/
    1030             : /*                          ReleaseResultSet()                          */
    1031             : /************************************************************************/
    1032             : 
    1033          84 : void OGRMySQLDataSource::ReleaseResultSet(OGRLayer *poLayer)
    1034             : 
    1035             : {
    1036          84 :     delete poLayer;
    1037          84 : }
    1038             : 
    1039             : /************************************************************************/
    1040             : /*                            LaunderName()                             */
    1041             : /************************************************************************/
    1042             : 
    1043         336 : char *OGRMySQLDataSource::LaunderName(const char *pszSrcName)
    1044             : 
    1045             : {
    1046         336 :     char *pszSafeName = CPLStrdup(pszSrcName);
    1047             : 
    1048        3760 :     for (int i = 0; pszSafeName[i] != '\0'; i++)
    1049             :     {
    1050        3424 :         pszSafeName[i] =
    1051        3424 :             (char)CPLTolower(static_cast<unsigned char>(pszSafeName[i]));
    1052        3424 :         if (pszSafeName[i] == '-' || pszSafeName[i] == '#')
    1053           0 :             pszSafeName[i] = '_';
    1054             :     }
    1055             : 
    1056         336 :     return pszSafeName;
    1057             : }
    1058             : 
    1059             : /************************************************************************/
    1060             : /*                         RequestLongResult()                          */
    1061             : /*                                                                      */
    1062             : /*      Layers need to use mysql_use_result() instead of                */
    1063             : /*      mysql_store_result() so that we won't have to load entire       */
    1064             : /*      result sets into RAM.  But only one "streamed" resultset can    */
    1065             : /*      be active on a database connection at a time.  So we need to    */
    1066             : /*      maintain a way of closing off an active streaming resultset     */
    1067             : /*      before any other sort of query with a resultset is              */
    1068             : /*      executable.  This method (and InterruptLongResult())            */
    1069             : /*      implement that exclusion.                                       */
    1070             : /************************************************************************/
    1071             : 
    1072         256 : void OGRMySQLDataSource::RequestLongResult(OGRMySQLLayer *poNewLayer)
    1073             : 
    1074             : {
    1075         256 :     InterruptLongResult();
    1076         256 :     poLongResultLayer = poNewLayer;
    1077         256 : }
    1078             : 
    1079             : /************************************************************************/
    1080             : /*                        InterruptLongResult()                         */
    1081             : /************************************************************************/
    1082             : 
    1083        1112 : void OGRMySQLDataSource::InterruptLongResult()
    1084             : 
    1085             : {
    1086        1112 :     if (poLongResultLayer != nullptr)
    1087             :     {
    1088         409 :         poLongResultLayer->ResetReading();
    1089         409 :         poLongResultLayer = nullptr;
    1090             :     }
    1091        1112 : }
    1092             : 
    1093             : /************************************************************************/
    1094             : /*                            DeleteLayer()                             */
    1095             : /************************************************************************/
    1096             : 
    1097           2 : OGRErr OGRMySQLDataSource::DeleteLayer(int iLayer)
    1098             : 
    1099             : {
    1100           2 :     if (iLayer < 0 || iLayer >= nLayers)
    1101           0 :         return OGRERR_FAILURE;
    1102             : 
    1103             :     /* -------------------------------------------------------------------- */
    1104             :     /*      Blow away our OGR structures related to the layer.  This is     */
    1105             :     /*      pretty dangerous if anything has a reference to this layer!     */
    1106             :     /* -------------------------------------------------------------------- */
    1107           4 :     CPLString osLayerName = papoLayers[iLayer]->GetLayerDefn()->GetName();
    1108             : 
    1109           2 :     CPLDebug("MYSQL", "DeleteLayer(%s)", osLayerName.c_str());
    1110             : 
    1111           2 :     delete papoLayers[iLayer];
    1112           2 :     memmove(papoLayers + iLayer, papoLayers + iLayer + 1,
    1113           2 :             sizeof(void *) * (nLayers - iLayer - 1));
    1114           2 :     nLayers--;
    1115             : 
    1116             :     /* -------------------------------------------------------------------- */
    1117             :     /*      Remove from the database.                                       */
    1118             :     /* -------------------------------------------------------------------- */
    1119           4 :     CPLString osCommand;
    1120             : 
    1121           2 :     osCommand.Printf("DROP TABLE `%s` ", osLayerName.c_str());
    1122             : 
    1123           2 :     if (!mysql_query(GetConn(), osCommand))
    1124             :     {
    1125           2 :         CPLDebug("MYSQL", "Dropped table %s.", osLayerName.c_str());
    1126           2 :         return OGRERR_NONE;
    1127             :     }
    1128             :     else
    1129             :     {
    1130           0 :         ReportError(osCommand);
    1131           0 :         return OGRERR_FAILURE;
    1132             :     }
    1133             : }
    1134             : 
    1135             : /************************************************************************/
    1136             : /*                           ICreateLayer()                             */
    1137             : /************************************************************************/
    1138             : 
    1139             : OGRLayer *
    1140         176 : OGRMySQLDataSource::ICreateLayer(const char *pszLayerNameIn,
    1141             :                                  const OGRGeomFieldDefn *poGeomFieldDefn,
    1142             :                                  CSLConstList papszOptions)
    1143             : 
    1144             : {
    1145         176 :     MYSQL_RES *hResult = nullptr;
    1146         352 :     CPLString osCommand;
    1147             :     const char *pszGeomColumnName;
    1148             :     const char *pszExpectedFIDName;
    1149             :     char *pszLayerName;
    1150             :     // int        nDimension = 3; // MySQL only supports 2d currently
    1151             : 
    1152             :     /* -------------------------------------------------------------------- */
    1153             :     /*      Make sure there isn't an active transaction already.            */
    1154             :     /* -------------------------------------------------------------------- */
    1155         176 :     InterruptLongResult();
    1156             : 
    1157         176 :     const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
    1158             :     const auto poSRS =
    1159         176 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
    1160             : 
    1161         176 :     if (CPLFetchBool(papszOptions, "LAUNDER", true))
    1162         176 :         pszLayerName = LaunderName(pszLayerNameIn);
    1163             :     else
    1164           0 :         pszLayerName = CPLStrdup(pszLayerNameIn);
    1165             : 
    1166             :     // if( wkbFlatten(eType) == eType )
    1167             :     //    nDimension = 2;
    1168             : 
    1169         176 :     CPLDebug("MYSQL", "Creating layer %s.", pszLayerName);
    1170             : 
    1171             :     /* -------------------------------------------------------------------- */
    1172             :     /*      Do we already have this layer?  If so, should we blow it        */
    1173             :     /*      away?                                                           */
    1174             :     /* -------------------------------------------------------------------- */
    1175             : 
    1176        3996 :     for (int iLayer = 0; iLayer < nLayers; iLayer++)
    1177             :     {
    1178        3820 :         if (EQUAL(pszLayerName, papoLayers[iLayer]->GetLayerDefn()->GetName()))
    1179             :         {
    1180             : 
    1181           4 :             if (CSLFetchNameValue(papszOptions, "OVERWRITE") != nullptr &&
    1182           2 :                 !EQUAL(CSLFetchNameValue(papszOptions, "OVERWRITE"), "NO"))
    1183             :             {
    1184           2 :                 DeleteLayer(iLayer);
    1185             :             }
    1186             :             else
    1187             :             {
    1188           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1189             :                          "Layer %s already exists, CreateLayer failed.\n"
    1190             :                          "Use the layer creation option OVERWRITE=YES to "
    1191             :                          "replace it.",
    1192             :                          pszLayerName);
    1193           0 :                 CPLFree(pszLayerName);
    1194           0 :                 return nullptr;
    1195             :             }
    1196             :         }
    1197             :     }
    1198             : 
    1199         176 :     pszGeomColumnName = CSLFetchNameValue(papszOptions, "GEOMETRY_NAME");
    1200         176 :     if (!pszGeomColumnName)
    1201         176 :         pszGeomColumnName = "SHAPE";
    1202             : 
    1203         176 :     pszExpectedFIDName = CSLFetchNameValue(papszOptions, "FID");
    1204         176 :     if (!pszExpectedFIDName)
    1205         176 :         pszExpectedFIDName = CSLFetchNameValue(papszOptions, "MYSQL_FID");
    1206         176 :     if (!pszExpectedFIDName)
    1207         176 :         pszExpectedFIDName = "OGR_FID";
    1208             : 
    1209         176 :     const bool bFID64 = CPLFetchBool(papszOptions, "FID64", false);
    1210         176 :     const char *pszFIDType = bFID64 ? "BIGINT" : "INT";
    1211             : 
    1212         176 :     CPLDebug("MYSQL", "Geometry Column Name %s.", pszGeomColumnName);
    1213         176 :     CPLDebug("MYSQL", "FID Column Name %s.", pszExpectedFIDName);
    1214             : 
    1215         176 :     const char *pszSI = CSLFetchNameValue(papszOptions, "SPATIAL_INDEX");
    1216             :     const bool bHasSI =
    1217         176 :         (eType != wkbNone && (pszSI == nullptr || CPLTestBool(pszSI)));
    1218             : 
    1219             :     // Calling this does no harm
    1220         176 :     InitializeMetadataTables();
    1221             : 
    1222             :     /* -------------------------------------------------------------------- */
    1223             :     /*      Try to get the SRS Id of this spatial reference system,         */
    1224             :     /*      adding to the srs table if needed.                             */
    1225             :     /* -------------------------------------------------------------------- */
    1226             : 
    1227         176 :     int nSRSId = GetUnknownSRID();
    1228         176 :     if (poSRS != nullptr)
    1229         162 :         nSRSId = FetchSRSId(poSRS);
    1230             : 
    1231         176 :     if (wkbFlatten(eType) == wkbNone)
    1232             :     {
    1233             :         osCommand.Printf("CREATE TABLE `%s` ( "
    1234             :                          "   %s %s UNIQUE NOT NULL AUTO_INCREMENT )",
    1235           4 :                          pszLayerName, pszExpectedFIDName, pszFIDType);
    1236             :     }
    1237             :     else
    1238             :     {
    1239             :         // when using mysql8 and SRS is specified, use SRID option for geometry.
    1240         172 :         if (GetMajorVersion() < 8 || IsMariaDB() || nSRSId == GetUnknownSRID())
    1241             :             osCommand.Printf("CREATE TABLE `%s` ( "
    1242             :                              "   %s %s UNIQUE NOT NULL AUTO_INCREMENT, "
    1243             :                              "   %s GEOMETRY %s)",
    1244             :                              pszLayerName, pszExpectedFIDName, pszFIDType,
    1245          57 :                              pszGeomColumnName, bHasSI ? "NOT NULL" : "");
    1246             :         else
    1247             :             osCommand.Printf("CREATE TABLE `%s` ( "
    1248             :                              "   %s %s UNIQUE NOT NULL AUTO_INCREMENT, "
    1249             :                              "   %s GEOMETRY %s /*!80003 SRID %d */)",
    1250             :                              pszLayerName, pszExpectedFIDName, pszFIDType,
    1251             :                              pszGeomColumnName, bHasSI ? "NOT NULL" : "",
    1252         115 :                              nSRSId);
    1253             :     }
    1254             : 
    1255         176 :     if (CSLFetchNameValue(papszOptions, "ENGINE") != nullptr)
    1256             :     {
    1257           0 :         osCommand += " ENGINE = ";
    1258           0 :         osCommand += CSLFetchNameValue(papszOptions, "ENGINE");
    1259             :     }
    1260             : 
    1261         176 :     if (!mysql_query(GetConn(), osCommand))
    1262             :     {
    1263         176 :         if (mysql_field_count(GetConn()) == 0)
    1264         176 :             CPLDebug("MYSQL", "Created table %s.", pszLayerName);
    1265             :         else
    1266             :         {
    1267           0 :             ReportError(osCommand);
    1268           0 :             return nullptr;
    1269             :         }
    1270             :     }
    1271             :     else
    1272             :     {
    1273           0 :         ReportError(osCommand);
    1274           0 :         return nullptr;
    1275             :     }
    1276             : 
    1277             :     // make sure to attempt to free results of successful queries
    1278         176 :     hResult = mysql_store_result(GetConn());
    1279         176 :     FreeResultAndNullify(hResult);
    1280             : 
    1281         176 :     if (UpdateMetadataTables(pszLayerName, eType, pszGeomColumnName, nSRSId) !=
    1282             :         OGRERR_NONE)
    1283           0 :         return nullptr;
    1284             : 
    1285             :     /* -------------------------------------------------------------------- */
    1286             :     /*      Create the spatial index.                                       */
    1287             :     /*                                                                      */
    1288             :     /*      We're doing this before we add geometry and record to the table */
    1289             :     /*      so this may not be exactly the best way to do it.               */
    1290             :     /* -------------------------------------------------------------------- */
    1291         176 :     if (bHasSI)
    1292             :     {
    1293             :         osCommand.Printf("ALTER TABLE `%s` ADD SPATIAL INDEX(`%s`) ",
    1294         170 :                          pszLayerName, pszGeomColumnName);
    1295             : 
    1296         170 :         if (mysql_query(GetConn(), osCommand))
    1297             :         {
    1298           0 :             ReportError(osCommand);
    1299           0 :             return nullptr;
    1300             :         }
    1301             : 
    1302             :         // make sure to attempt to free results of successful queries
    1303         170 :         hResult = mysql_store_result(GetConn());
    1304         170 :         FreeResultAndNullify(hResult);
    1305             :     }
    1306             : 
    1307             :     /* -------------------------------------------------------------------- */
    1308             :     /*      Create the layer object.                                        */
    1309             :     /* -------------------------------------------------------------------- */
    1310             :     OGRMySQLTableLayer *poLayer;
    1311             :     OGRErr eErr;
    1312             : 
    1313         176 :     poLayer = new OGRMySQLTableLayer(this, pszLayerName, TRUE, nSRSId);
    1314         176 :     eErr = poLayer->Initialize(pszLayerName);
    1315         176 :     if (eErr == OGRERR_FAILURE)
    1316           0 :         return nullptr;
    1317         176 :     if (eType != wkbNone)
    1318         172 :         poLayer->GetLayerDefn()->GetGeomFieldDefn(0)->SetNullable(FALSE);
    1319             : 
    1320         176 :     poLayer->SetLaunderFlag(CPLFetchBool(papszOptions, "LAUNDER", true));
    1321         176 :     poLayer->SetPrecisionFlag(CPLFetchBool(papszOptions, "PRECISION", true));
    1322             : 
    1323             :     /* -------------------------------------------------------------------- */
    1324             :     /*      Add layer to data source layer list.                            */
    1325             :     /* -------------------------------------------------------------------- */
    1326         352 :     papoLayers = (OGRMySQLLayer **)CPLRealloc(
    1327         176 :         papoLayers, sizeof(OGRMySQLLayer *) * (nLayers + 1));
    1328             : 
    1329         176 :     papoLayers[nLayers++] = poLayer;
    1330             : 
    1331         176 :     CPLFree(pszLayerName);
    1332             : 
    1333         176 :     return poLayer;
    1334             : }
    1335             : 
    1336             : /************************************************************************/
    1337             : /*                     OGRMySQLEscapeLiteral()                          */
    1338             : /************************************************************************/
    1339             : 
    1340         209 : std::string OGRMySQLEscapeLiteral(const char *pszLiteral)
    1341             : {
    1342         209 :     std::string osVal;
    1343       21258 :     for (int i = 0; pszLiteral[i] != '\0'; i++)
    1344             :     {
    1345       21049 :         if (pszLiteral[i] == '\'')
    1346           0 :             osVal += '\'';
    1347       21049 :         osVal += pszLiteral[i];
    1348             :     }
    1349         209 :     return osVal;
    1350             : }

Generated by: LCOV version 1.14