Coverage Report

Created: 2025-07-23 09:13

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