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

Generated by: LCOV version 1.14