LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mysql - ogrmysqllayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 119 130 91.5 %
Date: 2024-11-21 22:18:42 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRMySQLLayer 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             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "ogr_mysql.h"
      15             : #include "cpl_conv.h"
      16             : #include "cpl_string.h"
      17             : 
      18             : /************************************************************************/
      19             : /*                           OGRMySQLLayer()                            */
      20             : /************************************************************************/
      21             : 
      22         272 : OGRMySQLLayer::OGRMySQLLayer(OGRMySQLDataSource *poDSIn) : poDS(poDSIn)
      23             : {
      24         272 : }
      25             : 
      26             : /************************************************************************/
      27             : /*                           ~OGRMySQLLayer()                           */
      28             : /************************************************************************/
      29             : 
      30         272 : OGRMySQLLayer::~OGRMySQLLayer()
      31             : 
      32             : {
      33         272 :     if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr)
      34             :     {
      35         470 :         CPLDebug("MySQL", "%d features read on layer '%s'.",
      36         235 :                  (int)m_nFeaturesRead, poFeatureDefn->GetName());
      37             :     }
      38             : 
      39         272 :     if (poFeatureDefn && poFeatureDefn->GetGeomFieldCount() > 0)
      40             :     {
      41           0 :         auto poGeomFieldDefn = dynamic_cast<OGRMySQLGeomFieldDefn *>(
      42         194 :             poFeatureDefn->GetGeomFieldDefn(0));
      43         194 :         if (poGeomFieldDefn)
      44         194 :             poGeomFieldDefn->UnsetDataSource();
      45             :     }
      46             : 
      47         272 :     OGRMySQLLayer::ResetReading();
      48             : 
      49         272 :     CPLFree(pszGeomColumn);
      50         272 :     CPLFree(pszGeomColumnTable);
      51         272 :     CPLFree(pszFIDColumn);
      52         272 :     CPLFree(pszQueryStatement);
      53             : 
      54         272 :     if (poFeatureDefn)
      55         272 :         poFeatureDefn->Release();
      56         272 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                            ResetReading()                            */
      60             : /************************************************************************/
      61             : 
      62        1189 : void OGRMySQLLayer::ResetReading()
      63             : 
      64             : {
      65        1189 :     iNextShapeId = 0;
      66             : 
      67        1189 :     if (hResultSet != nullptr)
      68             :     {
      69         335 :         mysql_free_result(hResultSet);
      70         335 :         hResultSet = nullptr;
      71             : 
      72         335 :         poDS->InterruptLongResult();
      73             :     }
      74        1189 :     m_bEOF = false;
      75        1189 : }
      76             : 
      77             : /************************************************************************/
      78             : /*                           GetNextFeature()                           */
      79             : /************************************************************************/
      80             : 
      81         710 : OGRFeature *OGRMySQLLayer::GetNextFeature()
      82             : 
      83             : {
      84         710 :     if (m_bEOF)
      85           2 :         return nullptr;
      86             : 
      87             :     while (true)
      88             :     {
      89             :         OGRFeature *poFeature;
      90             : 
      91         712 :         poFeature = GetNextRawFeature();
      92         712 :         if (poFeature == nullptr)
      93             :         {
      94          63 :             m_bEOF = true;
      95          63 :             return nullptr;
      96             :         }
      97             : 
      98        1380 :         if ((m_poFilterGeom == nullptr ||
      99        1294 :              FilterGeometry(poFeature->GetGeometryRef())) &&
     100         645 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     101         645 :             return poFeature;
     102             : 
     103           4 :         delete poFeature;
     104           4 :     }
     105             : }
     106             : 
     107             : /************************************************************************/
     108             : /*                          RecordToFeature()                           */
     109             : /*                                                                      */
     110             : /*      Convert the indicated record of the current result set into     */
     111             : /*      a feature.                                                      */
     112             : /************************************************************************/
     113             : 
     114         685 : OGRFeature *OGRMySQLLayer::RecordToFeature(char **papszRow,
     115             :                                            unsigned long *panLengths)
     116             : 
     117             : {
     118         685 :     mysql_field_seek(hResultSet, 0);
     119             : 
     120             :     /* -------------------------------------------------------------------- */
     121             :     /*      Create a feature from the current result.                       */
     122             :     /* -------------------------------------------------------------------- */
     123         685 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     124             : 
     125         685 :     poFeature->SetFID(iNextShapeId);
     126         685 :     m_nFeaturesRead++;
     127             : 
     128             :     /* ==================================================================== */
     129             :     /*      Transfer all result fields we can.                              */
     130             :     /* ==================================================================== */
     131        4109 :     for (int iField = 0; iField < (int)mysql_num_fields(hResultSet); iField++)
     132             :     {
     133        3424 :         MYSQL_FIELD *psMSField = mysql_fetch_field(hResultSet);
     134             : 
     135             :         /* --------------------------------------------------------------------
     136             :          */
     137             :         /*      Handle FID. */
     138             :         /* --------------------------------------------------------------------
     139             :          */
     140        3424 :         if (bHasFid && EQUAL(psMSField->name, pszFIDColumn))
     141             :         {
     142         569 :             if (papszRow[iField] == nullptr)
     143             :             {
     144           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     145             :                          "NULL primary key in RecordToFeature()");
     146           0 :                 return nullptr;
     147             :             }
     148             : 
     149         569 :             poFeature->SetFID(CPLAtoGIntBig(papszRow[iField]));
     150             :         }
     151             : 
     152        3424 :         if (papszRow[iField] == nullptr)
     153             :         {
     154         476 :             const int iOGRField = poFeatureDefn->GetFieldIndex(psMSField->name);
     155         476 :             if (iOGRField >= 0)
     156         474 :                 poFeature->SetFieldNull(iOGRField);
     157             : 
     158         476 :             continue;
     159             :         }
     160             : 
     161             :         /* --------------------------------------------------------------------
     162             :          */
     163             :         /*      Handle MySQL geometry */
     164             :         /* --------------------------------------------------------------------
     165             :          */
     166        2948 :         if (pszGeomColumn && EQUAL(psMSField->name, pszGeomColumn))
     167             :         {
     168         565 :             OGRGeometry *poGeometry = nullptr;
     169             : 
     170             :             // Geometry columns will have the first 4 bytes contain the SRID.
     171         565 :             OGRGeometryFactory::createFromWkb(
     172         565 :                 papszRow[iField] + 4, nullptr, &poGeometry,
     173         565 :                 static_cast<int>(panLengths[iField] - 4));
     174             : 
     175         565 :             if (poGeometry != nullptr)
     176             :             {
     177         565 :                 poGeometry->assignSpatialReference(GetSpatialRef());
     178         565 :                 poFeature->SetGeometryDirectly(poGeometry);
     179             :             }
     180         565 :             continue;
     181             :         }
     182             : 
     183             :         /* --------------------------------------------------------------------
     184             :          */
     185             :         /*      Transfer regular data fields. */
     186             :         /* --------------------------------------------------------------------
     187             :          */
     188        2383 :         const int iOGRField = poFeatureDefn->GetFieldIndex(psMSField->name);
     189        2383 :         if (iOGRField < 0)
     190         555 :             continue;
     191             : 
     192        1828 :         OGRFieldDefn *psFieldDefn = poFeatureDefn->GetFieldDefn(iOGRField);
     193             : 
     194        1828 :         if (psFieldDefn->GetType() == OFTBinary)
     195             :         {
     196           0 :             poFeature->SetField(iOGRField, static_cast<int>(panLengths[iField]),
     197           0 :                                 (GByte *)papszRow[iField]);
     198             :         }
     199             :         else
     200             :         {
     201        1828 :             poFeature->SetField(iOGRField, papszRow[iField]);
     202             :         }
     203             :     }
     204             : 
     205         685 :     return poFeature;
     206             : }
     207             : 
     208             : /************************************************************************/
     209             : /*                         GetNextRawFeature()                          */
     210             : /************************************************************************/
     211             : 
     212         712 : OGRFeature *OGRMySQLLayer::GetNextRawFeature()
     213             : 
     214             : {
     215             :     /* -------------------------------------------------------------------- */
     216             :     /*      Do we need to establish an initial query?                       */
     217             :     /* -------------------------------------------------------------------- */
     218         712 :     if (iNextShapeId == 0 && hResultSet == nullptr)
     219             :     {
     220         256 :         CPLAssert(pszQueryStatement != nullptr);
     221             : 
     222         256 :         poDS->RequestLongResult(this);
     223             : 
     224         256 :         if (mysql_query(poDS->GetConn(), pszQueryStatement))
     225             :         {
     226           1 :             poDS->ReportError(pszQueryStatement);
     227           1 :             return nullptr;
     228             :         }
     229             : 
     230         255 :         hResultSet = mysql_use_result(poDS->GetConn());
     231         255 :         if (hResultSet == nullptr)
     232             :         {
     233           0 :             poDS->ReportError("mysql_use_result() failed on query.");
     234           0 :             return nullptr;
     235             :         }
     236             :     }
     237             : 
     238             :     /* -------------------------------------------------------------------- */
     239             :     /*      Fetch next record.                                              */
     240             :     /* -------------------------------------------------------------------- */
     241             :     char **papszRow;
     242             :     unsigned long *panLengths;
     243             : 
     244         711 :     papszRow = mysql_fetch_row(hResultSet);
     245         711 :     if (papszRow == nullptr)
     246             :     {
     247          62 :         ResetReading();
     248          62 :         return nullptr;
     249             :     }
     250             : 
     251         649 :     panLengths = mysql_fetch_lengths(hResultSet);
     252             : 
     253             :     /* -------------------------------------------------------------------- */
     254             :     /*      Process record.                                                 */
     255             :     /* -------------------------------------------------------------------- */
     256         649 :     OGRFeature *poFeature = RecordToFeature(papszRow, panLengths);
     257             : 
     258         649 :     iNextShapeId++;
     259             : 
     260         649 :     return poFeature;
     261             : }
     262             : 
     263             : /************************************************************************/
     264             : /*                             GetFeature()                             */
     265             : /*                                                                      */
     266             : /*      Note that we actually override this in OGRMySQLTableLayer.      */
     267             : /************************************************************************/
     268             : 
     269           0 : OGRFeature *OGRMySQLLayer::GetFeature(GIntBig nFeatureId)
     270             : 
     271             : {
     272           0 :     return OGRLayer::GetFeature(nFeatureId);
     273             : }
     274             : 
     275             : /************************************************************************/
     276             : /*                            GetFIDColumn()                            */
     277             : /************************************************************************/
     278             : 
     279          24 : const char *OGRMySQLLayer::GetFIDColumn()
     280             : 
     281             : {
     282          24 :     if (pszFIDColumn != nullptr)
     283          24 :         return pszFIDColumn;
     284             :     else
     285           0 :         return "";
     286             : }
     287             : 
     288             : /************************************************************************/
     289             : /*                         FetchSRSId()                                 */
     290             : /************************************************************************/
     291             : 
     292         194 : int OGRMySQLLayer::FetchSRSId()
     293             : {
     294         194 :     CPLString osCommand;
     295             :     char **papszRow;
     296             : 
     297         194 :     if (hResultSet != nullptr)
     298          11 :         mysql_free_result(hResultSet);
     299         194 :     hResultSet = nullptr;
     300             : 
     301         194 :     if (poDS->GetMajorVersion() < 8 || poDS->IsMariaDB())
     302             :     {
     303             :         osCommand.Printf("SELECT srid FROM geometry_columns "
     304             :                          "WHERE f_table_name = '%s'",
     305          63 :                          pszGeomColumnTable);
     306             :     }
     307             :     else
     308             :     {
     309             :         osCommand.Printf(
     310             :             "SELECT SRS_ID FROM INFORMATION_SCHEMA.ST_GEOMETRY_COLUMNS "
     311             :             "WHERE TABLE_NAME = '%s'",
     312         131 :             pszGeomColumnTable);
     313             :     }
     314             : 
     315         194 :     if (!mysql_query(poDS->GetConn(), osCommand))
     316         193 :         hResultSet = mysql_store_result(poDS->GetConn());
     317             : 
     318         194 :     papszRow = nullptr;
     319         194 :     if (hResultSet != nullptr)
     320         193 :         papszRow = mysql_fetch_row(hResultSet);
     321             : 
     322         194 :     if (papszRow != nullptr && papszRow[0] != nullptr)
     323             :     {
     324         178 :         nSRSId = atoi(papszRow[0]);
     325             :     }
     326             : 
     327             :     // make sure to free our results
     328         194 :     if (hResultSet != nullptr)
     329         193 :         mysql_free_result(hResultSet);
     330         194 :     hResultSet = nullptr;
     331             : 
     332         388 :     return nSRSId;
     333             : }
     334             : 
     335             : /************************************************************************/
     336             : /*                           GetSpatialRef()                            */
     337             : /************************************************************************/
     338             : 
     339        1077 : const OGRSpatialReference *OGRMySQLGeomFieldDefn::GetSpatialRef() const
     340             : 
     341             : {
     342        1077 :     if (!poDS)
     343           0 :         return poSRS;
     344             : 
     345        1077 :     if (poSRS == nullptr && nSRSId > -1)
     346             :     {
     347         172 :         poSRS = poDS->FetchSRS(nSRSId);
     348         172 :         if (poSRS != nullptr)
     349         168 :             const_cast<OGRSpatialReference *>(poSRS)->Reference();
     350             :         else
     351           4 :             nSRSId = poDS->GetUnknownSRID();
     352             :     }
     353             : 
     354        1077 :     return poSRS;
     355             : }
     356             : 
     357             : /************************************************************************/
     358             : /*                             GetDataset()                             */
     359             : /************************************************************************/
     360             : 
     361           2 : GDALDataset *OGRMySQLLayer::GetDataset()
     362             : {
     363           2 :     return poDS;
     364             : }

Generated by: LCOV version 1.14