LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/carto - ogrcartolayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 167 216 77.3 %
Date: 2024-11-21 22:18:42 Functions: 11 13 84.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Carto Translator
       4             :  * Purpose:  Implements OGRCARTOLayer class.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_carto.h"
      14             : #include "ogr_p.h"
      15             : #include "ogrlibjsonutils.h"
      16             : 
      17             : /************************************************************************/
      18             : /*                         OGRCARTOLayer()                            */
      19             : /************************************************************************/
      20             : 
      21         102 : OGRCARTOLayer::OGRCARTOLayer(OGRCARTODataSource *poDSIn)
      22             :     : poDS(poDSIn), poFeatureDefn(nullptr), bEOF(false), nFetchedObjects(-1),
      23             :       iNextInFetchedObjects(0), m_nNextFID(0), m_nNextOffset(0),
      24         102 :       poCachedObj(nullptr)
      25             : {
      26         102 : }
      27             : 
      28             : /************************************************************************/
      29             : /*                         ~OGRCARTOLayer()                           */
      30             : /************************************************************************/
      31             : 
      32         102 : OGRCARTOLayer::~OGRCARTOLayer()
      33             : 
      34             : {
      35         102 :     if (poCachedObj != nullptr)
      36          60 :         json_object_put(poCachedObj);
      37             : 
      38         102 :     if (poFeatureDefn != nullptr)
      39          87 :         poFeatureDefn->Release();
      40         102 : }
      41             : 
      42             : /************************************************************************/
      43             : /*                            ResetReading()                            */
      44             : /************************************************************************/
      45             : 
      46          32 : void OGRCARTOLayer::ResetReading()
      47             : 
      48             : {
      49          32 :     if (poCachedObj != nullptr)
      50           5 :         json_object_put(poCachedObj);
      51          32 :     poCachedObj = nullptr;
      52          32 :     bEOF = false;
      53          32 :     nFetchedObjects = -1;
      54          32 :     iNextInFetchedObjects = 0;
      55          32 :     m_nNextOffset = 0;
      56          32 :     m_nNextFID = 0;
      57          32 : }
      58             : 
      59             : /************************************************************************/
      60             : /*                           GetLayerDefn()                             */
      61             : /************************************************************************/
      62             : 
      63         246 : OGRFeatureDefn *OGRCARTOLayer::GetLayerDefn()
      64             : {
      65         246 :     return GetLayerDefnInternal(nullptr);
      66             : }
      67             : 
      68             : /************************************************************************/
      69             : /*                           BuildFeature()                             */
      70             : /************************************************************************/
      71             : 
      72         150 : OGRFeature *OGRCARTOLayer::BuildFeature(json_object *poRowObj)
      73             : {
      74         150 :     OGRFeature *poFeature = nullptr;
      75         300 :     if (poRowObj != nullptr &&
      76         150 :         json_object_get_type(poRowObj) == json_type_object)
      77             :     {
      78             :         // CPLDebug("Carto", "Row: %s", json_object_to_json_string(poRowObj));
      79         150 :         poFeature = new OGRFeature(poFeatureDefn);
      80             : 
      81         150 :         if (!osFIDColName.empty())
      82             :         {
      83             :             json_object *poVal =
      84           9 :                 CPL_json_object_object_get(poRowObj, osFIDColName);
      85          17 :             if (poVal != nullptr &&
      86           8 :                 json_object_get_type(poVal) == json_type_int)
      87             :             {
      88           8 :                 poFeature->SetFID(json_object_get_int64(poVal));
      89             :             }
      90             :         }
      91             :         else
      92             :         {
      93         141 :             poFeature->SetFID(m_nNextFID);
      94             :         }
      95             : 
      96        1329 :         for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
      97             :         {
      98        1179 :             json_object *poVal = CPL_json_object_object_get(
      99        1179 :                 poRowObj, poFeatureDefn->GetFieldDefn(i)->GetNameRef());
     100        1179 :             if (poVal == nullptr)
     101             :             {
     102         894 :                 poFeature->SetFieldNull(i);
     103             :             }
     104         285 :             else if (json_object_get_type(poVal) == json_type_string)
     105             :             {
     106         253 :                 if (poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
     107             :                 {
     108             :                     OGRField sField;
     109           1 :                     if (OGRParseXMLDateTime(json_object_get_string(poVal),
     110           1 :                                             &sField))
     111             :                     {
     112           1 :                         poFeature->SetField(i, &sField);
     113             :                     }
     114             :                 }
     115             :                 else
     116             :                 {
     117         252 :                     poFeature->SetField(i, json_object_get_string(poVal));
     118             :                 }
     119             :             }
     120          46 :             else if (json_object_get_type(poVal) == json_type_int ||
     121          14 :                      json_object_get_type(poVal) == json_type_boolean)
     122             :             {
     123          31 :                 poFeature->SetField(i, (GIntBig)json_object_get_int64(poVal));
     124             :             }
     125           1 :             else if (json_object_get_type(poVal) == json_type_double)
     126             :             {
     127           1 :                 poFeature->SetField(i, json_object_get_double(poVal));
     128             :             }
     129             :         }
     130             : 
     131         159 :         for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
     132             :         {
     133             :             OGRGeomFieldDefn *poGeomFldDefn =
     134           9 :                 poFeatureDefn->GetGeomFieldDefn(i);
     135           9 :             json_object *poVal = CPL_json_object_object_get(
     136             :                 poRowObj, poGeomFldDefn->GetNameRef());
     137          11 :             if (poVal != nullptr &&
     138           2 :                 json_object_get_type(poVal) == json_type_string)
     139             :             {
     140           2 :                 OGRGeometry *poGeom = OGRGeometryFromHexEWKB(
     141             :                     json_object_get_string(poVal), nullptr, FALSE);
     142           2 :                 if (poGeom != nullptr)
     143           2 :                     poGeom->assignSpatialReference(
     144           2 :                         poGeomFldDefn->GetSpatialRef());
     145           2 :                 poFeature->SetGeomFieldDirectly(i, poGeom);
     146             :             }
     147             :         }
     148             :     }
     149         150 :     return poFeature;
     150             : }
     151             : 
     152             : /************************************************************************/
     153             : /*                        FetchNewFeatures()                            */
     154             : /************************************************************************/
     155             : 
     156          83 : json_object *OGRCARTOLayer::FetchNewFeatures()
     157             : {
     158         166 :     CPLString osSQL = osBaseSQL;
     159         166 :     if (osSQL.ifind("SELECT") != std::string::npos &&
     160          83 :         osSQL.ifind(" LIMIT ") == std::string::npos)
     161             :     {
     162          83 :         osSQL += " LIMIT ";
     163          83 :         osSQL += CPLSPrintf("%d", GetFeaturesToFetch());
     164          83 :         osSQL += " OFFSET ";
     165          83 :         osSQL += CPLSPrintf(CPL_FRMT_GIB, m_nNextOffset);
     166             :     }
     167         166 :     return poDS->RunSQL(osSQL);
     168             : }
     169             : 
     170             : /************************************************************************/
     171             : /*                        GetNextRawFeature()                           */
     172             : /************************************************************************/
     173             : 
     174         226 : OGRFeature *OGRCARTOLayer::GetNextRawFeature()
     175             : {
     176         226 :     if (bEOF)
     177          13 :         return nullptr;
     178             : 
     179         213 :     if (iNextInFetchedObjects >= nFetchedObjects)
     180             :     {
     181         131 :         if (nFetchedObjects > 0 && nFetchedObjects < GetFeaturesToFetch())
     182             :         {
     183          32 :             bEOF = true;
     184          32 :             return nullptr;
     185             :         }
     186             : 
     187          99 :         if (poFeatureDefn == nullptr && osBaseSQL.empty())
     188             :         {
     189           0 :             GetLayerDefn();
     190             :         }
     191             : 
     192          99 :         json_object *poObj = FetchNewFeatures();
     193          99 :         if (poObj == nullptr)
     194             :         {
     195          23 :             bEOF = true;
     196          23 :             return nullptr;
     197             :         }
     198             : 
     199          76 :         if (poFeatureDefn == nullptr)
     200             :         {
     201          68 :             GetLayerDefnInternal(poObj);
     202             :         }
     203             : 
     204          76 :         json_object *poRows = CPL_json_object_object_get(poObj, "rows");
     205         144 :         if (poRows == nullptr ||
     206         144 :             json_object_get_type(poRows) != json_type_array ||
     207          68 :             json_object_array_length(poRows) == 0)
     208             :         {
     209          10 :             json_object_put(poObj);
     210          10 :             bEOF = true;
     211          10 :             return nullptr;
     212             :         }
     213             : 
     214          66 :         if (poCachedObj != nullptr)
     215           1 :             json_object_put(poCachedObj);
     216          66 :         poCachedObj = poObj;
     217             : 
     218          66 :         nFetchedObjects = static_cast<decltype(nFetchedObjects)>(
     219          66 :             json_object_array_length(poRows));
     220          66 :         iNextInFetchedObjects = 0;
     221             :     }
     222             : 
     223         148 :     json_object *poRows = CPL_json_object_object_get(poCachedObj, "rows");
     224             :     json_object *poRowObj =
     225         148 :         json_object_array_get_idx(poRows, iNextInFetchedObjects);
     226             : 
     227         148 :     iNextInFetchedObjects++;
     228             : 
     229         148 :     OGRFeature *poFeature = BuildFeature(poRowObj);
     230         148 :     m_nNextOffset++;
     231         148 :     m_nNextFID = poFeature->GetFID() + 1;
     232             : 
     233         148 :     return poFeature;
     234             : }
     235             : 
     236             : /************************************************************************/
     237             : /*                           GetNextFeature()                           */
     238             : /************************************************************************/
     239             : 
     240         285 : OGRFeature *OGRCARTOLayer::GetNextFeature()
     241             : {
     242             :     OGRFeature *poFeature;
     243             : 
     244             :     while (true)
     245             :     {
     246         285 :         poFeature = GetNextRawFeature();
     247         285 :         if (poFeature == nullptr)
     248          79 :             return nullptr;
     249             : 
     250         414 :         if ((m_poFilterGeom == nullptr ||
     251         412 :              FilterGeometry(poFeature->GetGeometryRef())) &&
     252         206 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     253             :         {
     254         206 :             return poFeature;
     255             :         }
     256             :         else
     257           0 :             delete poFeature;
     258             :     }
     259             : }
     260             : 
     261             : /************************************************************************/
     262             : /*                           TestCapability()                           */
     263             : /************************************************************************/
     264             : 
     265          16 : int OGRCARTOLayer::TestCapability(const char *pszCap)
     266             : 
     267             : {
     268          16 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
     269           0 :         return TRUE;
     270          16 :     return FALSE;
     271             : }
     272             : 
     273             : /************************************************************************/
     274             : /*                          EstablishLayerDefn()                        */
     275             : /************************************************************************/
     276             : 
     277          73 : void OGRCARTOLayer::EstablishLayerDefn(const char *pszLayerName,
     278             :                                        json_object *poObjIn)
     279             : {
     280          73 :     poFeatureDefn = new OGRFeatureDefn(pszLayerName);
     281          73 :     poFeatureDefn->Reference();
     282          73 :     poFeatureDefn->SetGeomType(wkbNone);
     283             : 
     284          73 :     CPLString osSQL;
     285          73 :     size_t nPos = osBaseSQL.ifind(" LIMIT ");
     286          73 :     if (nPos != std::string::npos)
     287             :     {
     288           0 :         osSQL = osBaseSQL;
     289           0 :         size_t nSize = osSQL.size();
     290           0 :         for (size_t i = nPos + strlen(" LIMIT "); i < nSize; i++)
     291             :         {
     292           0 :             if (osSQL[i] == ' ')
     293           0 :                 break;
     294           0 :             osSQL[i] = '0';
     295             :         }
     296             :     }
     297             :     else
     298          73 :         osSQL.Printf("%s LIMIT 0", osBaseSQL.c_str());
     299             :     json_object *poObj;
     300          73 :     if (poObjIn != nullptr)
     301          68 :         poObj = poObjIn;
     302             :     else
     303             :     {
     304           5 :         poObj = poDS->RunSQL(osSQL);
     305           5 :         if (poObj == nullptr)
     306             :         {
     307           3 :             return;
     308             :         }
     309             :     }
     310             : 
     311          70 :     json_object *poFields = CPL_json_object_object_get(poObj, "fields");
     312         139 :     if (poFields == nullptr ||
     313          69 :         json_object_get_type(poFields) != json_type_object)
     314             :     {
     315           2 :         if (poObjIn == nullptr)
     316           0 :             json_object_put(poObj);
     317           2 :         return;
     318             :     }
     319             : 
     320             :     json_object_iter it;
     321          68 :     it.key = nullptr;
     322          68 :     it.val = nullptr;
     323          68 :     it.entry = nullptr;
     324         237 :     json_object_object_foreachC(poFields, it)
     325             :     {
     326         169 :         const char *pszColName = it.key;
     327         338 :         if (it.val != nullptr &&
     328         169 :             json_object_get_type(it.val) == json_type_object)
     329             :         {
     330         168 :             json_object *poType = CPL_json_object_object_get(it.val, "type");
     331         334 :             if (poType != nullptr &&
     332         166 :                 json_object_get_type(poType) == json_type_string)
     333             :             {
     334         165 :                 const char *pszType = json_object_get_string(poType);
     335         165 :                 CPLDebug("CARTO", "%s : %s", pszColName, pszType);
     336         165 :                 if (EQUAL(pszType, "string") ||
     337          76 :                     EQUAL(pszType, "unknown(19)") /* name */)
     338             :                 {
     339         216 :                     OGRFieldDefn oFieldDefn(pszColName, OFTString);
     340         216 :                     poFeatureDefn->AddFieldDefn(&oFieldDefn);
     341             :                 }
     342          57 :                 else if (EQUAL(pszType, "number"))
     343             :                 {
     344          37 :                     if (!EQUAL(pszColName, "cartodb_id"))
     345             :                     {
     346          74 :                         OGRFieldDefn oFieldDefn(pszColName, OFTReal);
     347          37 :                         poFeatureDefn->AddFieldDefn(&oFieldDefn);
     348             :                     }
     349             :                     else
     350           0 :                         osFIDColName = pszColName;
     351             :                 }
     352          20 :                 else if (EQUAL(pszType, "date"))
     353             :                 {
     354           1 :                     if (!EQUAL(pszColName, "created_at") &&
     355           1 :                         !EQUAL(pszColName, "updated_at"))
     356             :                     {
     357           2 :                         OGRFieldDefn oFieldDefn(pszColName, OFTDateTime);
     358           1 :                         poFeatureDefn->AddFieldDefn(&oFieldDefn);
     359             :                     }
     360             :                 }
     361          19 :                 else if (EQUAL(pszType, "geometry"))
     362             :                 {
     363           0 :                     if (!EQUAL(pszColName, "the_geom_webmercator"))
     364             :                     {
     365             :                         auto poFieldDefn =
     366             :                             std::make_unique<OGRCartoGeomFieldDefn>(pszColName,
     367           0 :                                                                     wkbUnknown);
     368             :                         OGRSpatialReference *l_poSRS =
     369           0 :                             GetSRS(pszColName, &poFieldDefn->nSRID);
     370           0 :                         if (l_poSRS != nullptr)
     371             :                         {
     372           0 :                             poFieldDefn->SetSpatialRef(l_poSRS);
     373           0 :                             l_poSRS->Release();
     374             :                         }
     375           0 :                         poFeatureDefn->AddGeomFieldDefn(std::move(poFieldDefn));
     376             :                     }
     377             :                 }
     378          19 :                 else if (EQUAL(pszType, "boolean"))
     379             :                 {
     380          38 :                     OGRFieldDefn oFieldDefn(pszColName, OFTInteger);
     381          19 :                     oFieldDefn.SetSubType(OFSTBoolean);
     382          19 :                     poFeatureDefn->AddFieldDefn(&oFieldDefn);
     383             :                 }
     384             :                 else
     385             :                 {
     386           0 :                     CPLDebug("CARTO",
     387             :                              "Unhandled type: %s. Defaulting to string",
     388             :                              pszType);
     389           0 :                     OGRFieldDefn oFieldDefn(pszColName, OFTString);
     390           0 :                     poFeatureDefn->AddFieldDefn(&oFieldDefn);
     391             :                 }
     392             :             }
     393           4 :             else if (poType != nullptr &&
     394           1 :                      json_object_get_type(poType) == json_type_int)
     395             :             {
     396             :                 /* FIXME? manual creations of geometry columns return integer
     397             :                  * types */
     398             :                 auto poFieldDefn = std::make_unique<OGRCartoGeomFieldDefn>(
     399           0 :                     pszColName, wkbUnknown);
     400             :                 OGRSpatialReference *l_poSRS =
     401           0 :                     GetSRS(pszColName, &poFieldDefn->nSRID);
     402           0 :                 if (l_poSRS != nullptr)
     403             :                 {
     404           0 :                     poFieldDefn->SetSpatialRef(l_poSRS);
     405           0 :                     l_poSRS->Release();
     406             :                 }
     407           0 :                 poFeatureDefn->AddGeomFieldDefn(std::move(poFieldDefn));
     408             :             }
     409             :         }
     410             :     }
     411          68 :     if (poObjIn == nullptr)
     412           2 :         json_object_put(poObj);
     413             : }
     414             : 
     415             : /************************************************************************/
     416             : /*                               GetSRS()                               */
     417             : /************************************************************************/
     418             : 
     419           0 : OGRSpatialReference *OGRCARTOLayer::GetSRS(const char *pszGeomCol, int *pnSRID)
     420             : {
     421           0 :     json_object *poObj = poDS->RunSQL(GetSRS_SQL(pszGeomCol));
     422           0 :     json_object *poRowObj = OGRCARTOGetSingleRow(poObj);
     423           0 :     if (poRowObj == nullptr)
     424             :     {
     425           0 :         if (poObj != nullptr)
     426           0 :             json_object_put(poObj);
     427           0 :         return nullptr;
     428             :     }
     429             : 
     430           0 :     json_object *poSRID = CPL_json_object_object_get(poRowObj, "srid");
     431           0 :     if (poSRID != nullptr && json_object_get_type(poSRID) == json_type_int)
     432             :     {
     433           0 :         *pnSRID = json_object_get_int(poSRID);
     434             :     }
     435             : 
     436           0 :     json_object *poSRTEXT = CPL_json_object_object_get(poRowObj, "srtext");
     437           0 :     OGRSpatialReference *l_poSRS = nullptr;
     438           0 :     if (poSRTEXT != nullptr &&
     439           0 :         json_object_get_type(poSRTEXT) == json_type_string)
     440             :     {
     441           0 :         const char *pszSRTEXT = json_object_get_string(poSRTEXT);
     442           0 :         l_poSRS = new OGRSpatialReference();
     443           0 :         l_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     444           0 :         if (l_poSRS->importFromWkt(pszSRTEXT) != OGRERR_NONE)
     445             :         {
     446           0 :             delete l_poSRS;
     447           0 :             l_poSRS = nullptr;
     448             :         }
     449             :     }
     450           0 :     json_object_put(poObj);
     451             : 
     452           0 :     return l_poSRS;
     453             : }
     454             : 
     455             : /************************************************************************/
     456             : /*                             GetDataset()                             */
     457             : /************************************************************************/
     458             : 
     459           1 : GDALDataset *OGRCARTOLayer::GetDataset()
     460             : {
     461           1 :     return poDS;
     462             : }

Generated by: LCOV version 1.14