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