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