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