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