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