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