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 : }
|