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