Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: AmigoCloud Translator
4 : * Purpose: Implements OGRAmigoCloudTableLayer class.
5 : * Author: Even Rouault, <even dot rouault at spatialys.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 "ogr_pgdump.h"
32 : #include "ogrgeojsonreader.h"
33 : #include <sstream>
34 : #include <iomanip>
35 :
36 : /************************************************************************/
37 : /* OGRAMIGOCLOUDEscapeIdentifier( ) */
38 : /************************************************************************/
39 :
40 0 : CPLString OGRAMIGOCLOUDEscapeIdentifier(const char *pszStr)
41 : {
42 0 : CPLString osStr;
43 :
44 0 : osStr += "\"";
45 :
46 0 : char ch = '\0';
47 0 : for (int i = 0; (ch = pszStr[i]) != '\0'; i++)
48 : {
49 0 : if (ch == '"')
50 0 : osStr.append(1, ch);
51 0 : osStr.append(1, ch);
52 : }
53 :
54 0 : osStr += "\"";
55 :
56 0 : return osStr;
57 : }
58 :
59 0 : std::string OGRAMIGOCLOUDJsonEncode(const std::string &s)
60 : {
61 0 : std::ostringstream o;
62 0 : for (auto c = s.cbegin(); c != s.cend(); c++)
63 : {
64 0 : switch (*c)
65 : {
66 0 : case '"':
67 0 : o << "\\\"";
68 0 : break;
69 0 : case '\\':
70 0 : o << "\\\\";
71 0 : break;
72 0 : case '\b':
73 0 : o << "\\b";
74 0 : break;
75 0 : case '\f':
76 0 : o << "\\f";
77 0 : break;
78 0 : case '\n':
79 0 : o << "\\n";
80 0 : break;
81 0 : case '\r':
82 0 : o << "\\r";
83 0 : break;
84 0 : case '\t':
85 0 : o << "\\t";
86 0 : break;
87 0 : default:
88 0 : if (*c <= '\x1f')
89 : {
90 0 : o << "\\u" << std::hex << std::setw(4) << std::setfill('0')
91 0 : << (int)*c;
92 : }
93 : else
94 : {
95 0 : o << *c;
96 : }
97 : }
98 : }
99 0 : return o.str();
100 : }
101 :
102 : /************************************************************************/
103 : /* OGRAmigoCloudTableLayer() */
104 : /************************************************************************/
105 :
106 0 : OGRAmigoCloudTableLayer::OGRAmigoCloudTableLayer(
107 0 : OGRAmigoCloudDataSource *poDSIn, const char *pszName)
108 : : OGRAmigoCloudLayer(poDSIn), osDatasetId(CPLString(pszName)), nNextFID(-1),
109 0 : bDeferredCreation(FALSE)
110 : {
111 0 : osTableName = CPLString("dataset_") + osDatasetId;
112 0 : SetDescription(osDatasetId);
113 0 : osName = osDatasetId;
114 0 : nMaxChunkSize =
115 0 : atoi(CPLGetConfigOption("AMIGOCLOUD_MAX_CHUNK_SIZE", "15")) * 1024 *
116 : 1024;
117 0 : }
118 :
119 : /************************************************************************/
120 : /* ~OGRAmigoCloudTableLayer() */
121 : /************************************************************************/
122 :
123 0 : OGRAmigoCloudTableLayer::~OGRAmigoCloudTableLayer()
124 :
125 : {
126 0 : if (bDeferredCreation)
127 0 : RunDeferredCreationIfNecessary();
128 0 : FlushDeferredInsert();
129 0 : }
130 :
131 : /************************************************************************/
132 : /* GetLayerDefnInternal() */
133 : /************************************************************************/
134 :
135 : OGRFeatureDefn *
136 0 : OGRAmigoCloudTableLayer::GetLayerDefnInternal(CPL_UNUSED json_object *poObjIn)
137 : {
138 0 : if (poFeatureDefn != nullptr)
139 : {
140 0 : return poFeatureDefn;
141 : }
142 :
143 : osBaseSQL.Printf("SELECT * FROM %s",
144 0 : OGRAMIGOCLOUDEscapeIdentifier(osTableName).c_str());
145 0 : EstablishLayerDefn(osTableName, nullptr);
146 0 : osBaseSQL = "";
147 :
148 0 : if (!osFIDColName.empty())
149 : {
150 0 : CPLString sql;
151 : sql.Printf("SELECT %s FROM %s",
152 0 : OGRAMIGOCLOUDEscapeIdentifier(osFIDColName).c_str(),
153 0 : OGRAMIGOCLOUDEscapeIdentifier(osTableName).c_str());
154 0 : json_object *poObj = poDS->RunSQL(sql);
155 0 : if (poObj != nullptr && json_object_get_type(poObj) == json_type_object)
156 : {
157 0 : json_object *poRows = CPL_json_object_object_get(poObj, "data");
158 :
159 0 : if (poRows != nullptr &&
160 0 : json_object_get_type(poRows) == json_type_array)
161 : {
162 0 : mFIDs.clear();
163 0 : const auto nLength = json_object_array_length(poRows);
164 0 : for (auto i = decltype(nLength){0}; i < nLength; i++)
165 : {
166 0 : json_object *obj = json_object_array_get_idx(poRows, i);
167 :
168 : json_object_iter it;
169 0 : it.key = nullptr;
170 0 : it.val = nullptr;
171 0 : it.entry = nullptr;
172 0 : json_object_object_foreachC(obj, it)
173 : {
174 0 : const char *pszColName = it.key;
175 0 : if (it.val != nullptr)
176 : {
177 0 : if (EQUAL(pszColName, osFIDColName.c_str()))
178 : {
179 : std::string amigo_id =
180 0 : json_object_get_string(it.val);
181 0 : OGRAmigoCloudFID aFID(amigo_id, iNext);
182 0 : mFIDs[aFID.iFID] = aFID;
183 : }
184 : }
185 : }
186 : }
187 : }
188 0 : json_object_put(poObj);
189 : }
190 : }
191 :
192 0 : if (!osFIDColName.empty())
193 : {
194 0 : osBaseSQL = "SELECT ";
195 0 : osBaseSQL += OGRAMIGOCLOUDEscapeIdentifier(osFIDColName);
196 : }
197 0 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
198 : {
199 0 : if (osBaseSQL.empty())
200 0 : osBaseSQL = "SELECT ";
201 : else
202 0 : osBaseSQL += ", ";
203 0 : osBaseSQL += OGRAMIGOCLOUDEscapeIdentifier(
204 0 : poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
205 : }
206 0 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
207 : {
208 0 : if (osBaseSQL.empty())
209 0 : osBaseSQL = "SELECT ";
210 : else
211 0 : osBaseSQL += ", ";
212 0 : osBaseSQL += OGRAMIGOCLOUDEscapeIdentifier(
213 0 : poFeatureDefn->GetFieldDefn(i)->GetNameRef());
214 : }
215 0 : if (osBaseSQL.empty())
216 0 : osBaseSQL = "SELECT *";
217 0 : osBaseSQL += " FROM ";
218 0 : osBaseSQL += OGRAMIGOCLOUDEscapeIdentifier(osTableName);
219 :
220 0 : osSELECTWithoutWHERE = osBaseSQL;
221 :
222 0 : return poFeatureDefn;
223 : }
224 :
225 : /************************************************************************/
226 : /* FetchNewFeatures() */
227 : /************************************************************************/
228 :
229 0 : json_object *OGRAmigoCloudTableLayer::FetchNewFeatures(GIntBig iNextIn)
230 : {
231 0 : if (!osFIDColName.empty())
232 : {
233 0 : CPLString osSQL;
234 :
235 0 : if (!osWHERE.empty())
236 : {
237 : osSQL.Printf("%s WHERE %s ", osSELECTWithoutWHERE.c_str(),
238 0 : (!osWHERE.empty()) ? CPLSPrintf("%s", osWHERE.c_str())
239 0 : : "");
240 : }
241 : else
242 : {
243 0 : osSQL.Printf("%s", osSELECTWithoutWHERE.c_str());
244 : }
245 :
246 0 : if (osSQL.ifind("SELECT") != std::string::npos &&
247 0 : osSQL.ifind(" LIMIT ") == std::string::npos)
248 : {
249 0 : osSQL += " LIMIT ";
250 0 : osSQL += CPLSPrintf("%d", GetFeaturesToFetch());
251 0 : osSQL += " OFFSET ";
252 0 : osSQL += CPLSPrintf(CPL_FRMT_GIB, iNextIn);
253 : }
254 0 : return poDS->RunSQL(osSQL);
255 : }
256 : else
257 0 : return OGRAmigoCloudLayer::FetchNewFeatures(iNextIn);
258 : }
259 :
260 : /************************************************************************/
261 : /* GetNextRawFeature() */
262 : /************************************************************************/
263 :
264 0 : OGRFeature *OGRAmigoCloudTableLayer::GetNextRawFeature()
265 : {
266 0 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
267 0 : return nullptr;
268 0 : FlushDeferredInsert();
269 0 : return OGRAmigoCloudLayer::GetNextRawFeature();
270 : }
271 :
272 : /************************************************************************/
273 : /* SetAttributeFilter() */
274 : /************************************************************************/
275 :
276 0 : OGRErr OGRAmigoCloudTableLayer::SetAttributeFilter(const char *pszQuery)
277 :
278 : {
279 0 : GetLayerDefn();
280 :
281 0 : if (pszQuery == nullptr)
282 0 : osQuery = "";
283 : else
284 : {
285 0 : osQuery = "(";
286 0 : osQuery += pszQuery;
287 0 : osQuery += ")";
288 : }
289 :
290 0 : BuildWhere();
291 :
292 0 : ResetReading();
293 :
294 0 : return OGRERR_NONE;
295 : }
296 :
297 : /************************************************************************/
298 : /* SetSpatialFilter() */
299 : /************************************************************************/
300 :
301 0 : void OGRAmigoCloudTableLayer::SetSpatialFilter(int iGeomField,
302 : OGRGeometry *poGeomIn)
303 :
304 : {
305 0 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
306 0 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
307 : {
308 0 : if (iGeomField != 0)
309 : {
310 0 : CPLError(CE_Failure, CPLE_AppDefined,
311 : "Invalid geometry field index : %d", iGeomField);
312 : }
313 0 : return;
314 : }
315 0 : m_iGeomFieldFilter = iGeomField;
316 :
317 0 : if (InstallFilter(poGeomIn))
318 : {
319 0 : BuildWhere();
320 :
321 0 : ResetReading();
322 : }
323 : }
324 :
325 : /************************************************************************/
326 : /* FlushDeferredInsert() */
327 : /************************************************************************/
328 :
329 0 : void OGRAmigoCloudTableLayer::FlushDeferredInsert()
330 :
331 : {
332 0 : if (vsDeferredInsertChangesets.empty())
333 0 : return;
334 :
335 0 : std::stringstream url;
336 0 : url << std::string(poDS->GetAPIURL())
337 0 : << "/users/0/projects/" + std::string(poDS->GetProjectId()) +
338 0 : "/datasets/" + osDatasetId + "/submit_change";
339 :
340 0 : std::stringstream query;
341 :
342 0 : query << "{\"type\":\"DML\",\"entity\":\"" << osTableName << "\",";
343 0 : query << "\"parent\":null,\"action\":\"INSERT\",\"data\":[";
344 :
345 0 : int counter = 0;
346 0 : for (size_t i = 0; i < vsDeferredInsertChangesets.size(); i++)
347 : {
348 0 : if (counter > 0)
349 0 : query << ",";
350 0 : query << vsDeferredInsertChangesets[i].c_str();
351 0 : counter++;
352 : }
353 0 : query << "]}";
354 :
355 0 : std::stringstream changeset;
356 0 : changeset << "{\"change\": \"" << OGRAMIGOCLOUDJsonEncode(query.str())
357 0 : << "\"}";
358 :
359 : json_object *poObj =
360 0 : poDS->RunPOST(url.str().c_str(), changeset.str().c_str());
361 0 : if (poObj != nullptr)
362 0 : json_object_put(poObj);
363 :
364 0 : vsDeferredInsertChangesets.clear();
365 0 : nNextFID = -1;
366 : }
367 :
368 : /************************************************************************/
369 : /* CreateField() */
370 : /************************************************************************/
371 :
372 0 : OGRErr OGRAmigoCloudTableLayer::CreateField(const OGRFieldDefn *poFieldIn,
373 : CPL_UNUSED int bApproxOK)
374 : {
375 0 : GetLayerDefn();
376 :
377 0 : if (!poDS->IsReadWrite())
378 : {
379 0 : CPLError(CE_Failure, CPLE_AppDefined,
380 : "Operation not available in read-only mode");
381 0 : return OGRERR_FAILURE;
382 : }
383 :
384 0 : OGRFieldDefn oField(poFieldIn);
385 : /* -------------------------------------------------------------------- */
386 : /* Create the new field. */
387 : /* -------------------------------------------------------------------- */
388 :
389 0 : if (!bDeferredCreation)
390 : {
391 0 : CPLString osSQL;
392 : osSQL.Printf("ALTER TABLE %s ADD COLUMN %s %s",
393 0 : OGRAMIGOCLOUDEscapeIdentifier(osTableName).c_str(),
394 0 : OGRAMIGOCLOUDEscapeIdentifier(oField.GetNameRef()).c_str(),
395 0 : OGRPGCommonLayerGetType(oField, false, true).c_str());
396 0 : if (!oField.IsNullable())
397 0 : osSQL += " NOT NULL";
398 0 : if (oField.GetDefault() != nullptr && !oField.IsDefaultDriverSpecific())
399 : {
400 0 : osSQL += " DEFAULT ";
401 0 : osSQL += OGRPGCommonLayerGetPGDefault(&oField);
402 : }
403 :
404 0 : json_object *poObj = poDS->RunSQL(osSQL);
405 0 : if (poObj == nullptr)
406 0 : return OGRERR_FAILURE;
407 0 : json_object_put(poObj);
408 : }
409 :
410 0 : poFeatureDefn->AddFieldDefn(&oField);
411 :
412 0 : return OGRERR_NONE;
413 : }
414 :
415 : /************************************************************************/
416 : /* ICreateFeature() */
417 : /************************************************************************/
418 :
419 0 : OGRErr OGRAmigoCloudTableLayer::ICreateFeature(OGRFeature *poFeature)
420 :
421 : {
422 0 : if (bDeferredCreation)
423 : {
424 0 : if (RunDeferredCreationIfNecessary() != OGRERR_NONE)
425 0 : return OGRERR_FAILURE;
426 : }
427 :
428 0 : GetLayerDefn();
429 :
430 0 : if (!poDS->IsReadWrite())
431 : {
432 0 : CPLError(CE_Failure, CPLE_AppDefined,
433 : "Operation not available in read-only mode");
434 0 : return OGRERR_FAILURE;
435 : }
436 :
437 0 : std::stringstream record;
438 :
439 0 : record << "{\"new\":{";
440 :
441 0 : int counter = 0;
442 :
443 : // Add geometry field
444 0 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
445 : {
446 0 : if (poFeature->GetGeomFieldRef(i) == nullptr)
447 0 : continue;
448 :
449 : record << "\""
450 0 : << OGRAMIGOCLOUDJsonEncode(
451 0 : poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef())
452 0 : << "\":";
453 :
454 0 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
455 0 : if (poGeom == nullptr)
456 0 : continue;
457 :
458 : OGRAmigoCloudGeomFieldDefn *poGeomFieldDefn =
459 0 : (OGRAmigoCloudGeomFieldDefn *)poFeatureDefn->GetGeomFieldDefn(i);
460 0 : int nSRID = poGeomFieldDefn->nSRID;
461 0 : if (nSRID == 0)
462 0 : nSRID = 4326;
463 0 : char *pszEWKB = nullptr;
464 0 : if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon &&
465 0 : wkbFlatten(GetGeomType()) == wkbMultiPolygon)
466 : {
467 0 : OGRMultiPolygon *poNewGeom = new OGRMultiPolygon();
468 0 : poNewGeom->addGeometry(poGeom);
469 0 : pszEWKB = OGRGeometryToHexEWKB(poNewGeom, nSRID, 2, 1);
470 0 : delete poNewGeom;
471 : }
472 : else
473 :
474 0 : pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID, 2, 1);
475 0 : record << "\"" << pszEWKB << "\"";
476 0 : CPLFree(pszEWKB);
477 :
478 0 : counter++;
479 : }
480 :
481 0 : std::string amigo_id_value;
482 :
483 : // Add non-geometry field
484 0 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
485 : {
486 0 : std::string name = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
487 0 : std::string value = poFeature->GetFieldAsString(i);
488 :
489 0 : if (name == "amigo_id")
490 : {
491 0 : amigo_id_value = value;
492 0 : continue;
493 : }
494 0 : if (!poFeature->IsFieldSet(i))
495 0 : continue;
496 :
497 0 : if (counter > 0)
498 0 : record << ",";
499 :
500 0 : record << OGRAMIGOCLOUDEscapeIdentifier(name.c_str()) << ":";
501 :
502 0 : if (!poFeature->IsFieldNull(i))
503 : {
504 0 : OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
505 0 : if (eType == OFTString || eType == OFTDateTime ||
506 0 : eType == OFTDate || eType == OFTTime)
507 : {
508 0 : record << "\"" << OGRAMIGOCLOUDJsonEncode(value.c_str())
509 0 : << "\"";
510 : }
511 : else
512 0 : record << OGRAMIGOCLOUDJsonEncode(value.c_str());
513 : }
514 : else
515 0 : record << "null";
516 :
517 0 : counter++;
518 : }
519 :
520 0 : record << "},";
521 :
522 0 : if (!amigo_id_value.empty())
523 : {
524 0 : record << "\"amigo_id\":\"" << amigo_id_value << "\"";
525 : }
526 : else
527 : {
528 0 : record << "\"amigo_id\":null";
529 : }
530 :
531 0 : record << "}";
532 :
533 0 : vsDeferredInsertChangesets.push_back(record.str());
534 :
535 0 : return OGRERR_NONE;
536 : }
537 :
538 : /************************************************************************/
539 : /* ISetFeature() */
540 : /************************************************************************/
541 :
542 0 : OGRErr OGRAmigoCloudTableLayer::ISetFeature(OGRFeature *poFeature)
543 :
544 : {
545 0 : OGRErr eRet = OGRERR_FAILURE;
546 :
547 0 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
548 0 : return OGRERR_FAILURE;
549 0 : FlushDeferredInsert();
550 :
551 0 : GetLayerDefn();
552 :
553 0 : if (!poDS->IsReadWrite())
554 : {
555 0 : CPLError(CE_Failure, CPLE_AppDefined,
556 : "Operation not available in read-only mode");
557 0 : return OGRERR_FAILURE;
558 : }
559 :
560 0 : if (poFeature->GetFID() == OGRNullFID)
561 : {
562 0 : CPLError(CE_Failure, CPLE_AppDefined,
563 : "FID required on features given to SetFeature().");
564 0 : return OGRERR_FAILURE;
565 : }
566 :
567 0 : const auto it = mFIDs.find(poFeature->GetFID());
568 0 : if (it != mFIDs.end())
569 : {
570 0 : const OGRAmigoCloudFID &aFID = it->second;
571 :
572 0 : CPLString osSQL;
573 : osSQL.Printf("UPDATE %s SET ",
574 0 : OGRAMIGOCLOUDEscapeIdentifier(osTableName).c_str());
575 0 : bool bMustComma = false;
576 0 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
577 : {
578 0 : if (!poFeature->IsFieldSet(i))
579 0 : continue;
580 :
581 0 : if (bMustComma)
582 0 : osSQL += ", ";
583 : else
584 0 : bMustComma = true;
585 :
586 0 : osSQL += OGRAMIGOCLOUDEscapeIdentifier(
587 0 : poFeatureDefn->GetFieldDefn(i)->GetNameRef());
588 0 : osSQL += " = ";
589 :
590 0 : if (poFeature->IsFieldNull(i))
591 : {
592 0 : osSQL += "NULL";
593 : }
594 : else
595 : {
596 0 : OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
597 0 : if (eType == OFTString || eType == OFTDateTime ||
598 0 : eType == OFTDate || eType == OFTTime)
599 : {
600 0 : osSQL += "'";
601 : osSQL +=
602 0 : OGRAMIGOCLOUDJsonEncode(poFeature->GetFieldAsString(i));
603 0 : osSQL += "'";
604 : }
605 0 : else if ((eType == OFTInteger || eType == OFTInteger64) &&
606 0 : poFeatureDefn->GetFieldDefn(i)->GetSubType() ==
607 : OFSTBoolean)
608 : {
609 0 : osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
610 : }
611 : else
612 0 : osSQL += poFeature->GetFieldAsString(i);
613 : }
614 : }
615 :
616 0 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
617 : {
618 0 : if (bMustComma)
619 0 : osSQL += ", ";
620 : else
621 0 : bMustComma = true;
622 :
623 0 : osSQL += OGRAMIGOCLOUDEscapeIdentifier(
624 0 : poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
625 0 : osSQL += " = ";
626 :
627 0 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
628 0 : if (poGeom == nullptr)
629 : {
630 0 : osSQL += "NULL";
631 : }
632 : else
633 : {
634 : OGRAmigoCloudGeomFieldDefn *poGeomFieldDefn =
635 : (OGRAmigoCloudGeomFieldDefn *)
636 0 : poFeatureDefn->GetGeomFieldDefn(i);
637 0 : int nSRID = poGeomFieldDefn->nSRID;
638 0 : if (nSRID == 0)
639 0 : nSRID = 4326;
640 0 : char *pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID, 2, 1);
641 0 : osSQL += "'";
642 0 : osSQL += pszEWKB;
643 0 : osSQL += "'";
644 0 : CPLFree(pszEWKB);
645 : }
646 : }
647 :
648 0 : if (!bMustComma) // nothing to do
649 0 : return OGRERR_NONE;
650 :
651 : osSQL += CPLSPrintf(" WHERE %s = '%s'",
652 0 : OGRAMIGOCLOUDEscapeIdentifier(osFIDColName).c_str(),
653 0 : aFID.osAmigoId.c_str());
654 :
655 0 : std::stringstream changeset;
656 0 : changeset << "{\"query\": \"" << OGRAMIGOCLOUDJsonEncode(osSQL)
657 0 : << "\"}";
658 0 : std::stringstream url;
659 0 : url << std::string(poDS->GetAPIURL())
660 0 : << "/users/0/projects/" + std::string(poDS->GetProjectId()) +
661 0 : "/sql";
662 : json_object *poObj =
663 0 : poDS->RunPOST(url.str().c_str(), changeset.str().c_str());
664 :
665 0 : if (poObj != nullptr)
666 : {
667 : json_object *poTotalRows =
668 0 : CPL_json_object_object_get(poObj, "total_rows");
669 0 : if (poTotalRows != nullptr &&
670 0 : json_object_get_type(poTotalRows) == json_type_int)
671 : {
672 0 : int nTotalRows = json_object_get_int(poTotalRows);
673 0 : if (nTotalRows > 0)
674 : {
675 0 : eRet = OGRERR_NONE;
676 : }
677 : else
678 0 : eRet = OGRERR_NON_EXISTING_FEATURE;
679 : }
680 0 : json_object_put(poObj);
681 : }
682 : }
683 0 : return eRet;
684 : }
685 :
686 : /************************************************************************/
687 : /* DeleteFeature() */
688 : /************************************************************************/
689 :
690 0 : OGRErr OGRAmigoCloudTableLayer::DeleteFeature(GIntBig nFID)
691 :
692 : {
693 0 : OGRErr eRet = OGRERR_FAILURE;
694 :
695 0 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
696 0 : return OGRERR_FAILURE;
697 0 : FlushDeferredInsert();
698 :
699 0 : GetLayerDefn();
700 :
701 0 : if (!poDS->IsReadWrite())
702 : {
703 0 : CPLError(CE_Failure, CPLE_AppDefined,
704 : "Operation not available in read-only mode");
705 0 : return OGRERR_FAILURE;
706 : }
707 :
708 0 : if (osFIDColName.empty())
709 0 : return OGRERR_FAILURE;
710 :
711 0 : const auto it = mFIDs.find(nFID);
712 0 : if (it != mFIDs.end())
713 : {
714 0 : const OGRAmigoCloudFID &aFID = it->second;
715 :
716 0 : CPLString osSQL;
717 : osSQL.Printf("DELETE FROM %s WHERE %s = '%s'",
718 0 : OGRAMIGOCLOUDEscapeIdentifier(osTableName).c_str(),
719 0 : OGRAMIGOCLOUDEscapeIdentifier(osFIDColName).c_str(),
720 0 : aFID.osAmigoId.c_str());
721 :
722 0 : std::stringstream changeset;
723 0 : changeset << "{\"query\": \"" << OGRAMIGOCLOUDJsonEncode(osSQL)
724 0 : << "\"}";
725 0 : std::stringstream url;
726 0 : url << std::string(poDS->GetAPIURL())
727 0 : << "/users/0/projects/" + std::string(poDS->GetProjectId()) +
728 0 : "/sql";
729 : json_object *poObj =
730 0 : poDS->RunPOST(url.str().c_str(), changeset.str().c_str());
731 0 : if (poObj != nullptr)
732 : {
733 0 : json_object_put(poObj);
734 0 : eRet = OGRERR_NONE;
735 : }
736 : }
737 0 : return eRet;
738 : }
739 :
740 : /************************************************************************/
741 : /* GetSRS_SQL() */
742 : /************************************************************************/
743 :
744 0 : CPLString OGRAmigoCloudTableLayer::GetSRS_SQL(const char *pszGeomCol)
745 : {
746 0 : CPLString osSQL;
747 :
748 : osSQL.Printf("SELECT srid, srtext FROM spatial_ref_sys WHERE srid IN "
749 : "(SELECT Find_SRID('%s', '%s', '%s'))",
750 0 : OGRAMIGOCLOUDJsonEncode(poDS->GetCurrentSchema()).c_str(),
751 0 : OGRAMIGOCLOUDJsonEncode(osTableName).c_str(),
752 0 : OGRAMIGOCLOUDJsonEncode(pszGeomCol).c_str());
753 :
754 0 : return osSQL;
755 : }
756 :
757 : /************************************************************************/
758 : /* BuildWhere() */
759 : /* */
760 : /* Build the WHERE statement appropriate to the current set of */
761 : /* criteria (spatial and attribute queries). */
762 : /************************************************************************/
763 :
764 0 : void OGRAmigoCloudTableLayer::BuildWhere()
765 :
766 : {
767 0 : osWHERE = "";
768 :
769 0 : if (m_poFilterGeom != nullptr && m_iGeomFieldFilter >= 0 &&
770 0 : m_iGeomFieldFilter < poFeatureDefn->GetGeomFieldCount())
771 : {
772 0 : OGREnvelope sEnvelope;
773 :
774 0 : m_poFilterGeom->getEnvelope(&sEnvelope);
775 :
776 : CPLString osGeomColumn(
777 0 : poFeatureDefn->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef());
778 :
779 : char szBox3D_1[128];
780 : char szBox3D_2[128];
781 0 : char *pszComma = nullptr;
782 :
783 0 : CPLsnprintf(szBox3D_1, sizeof(szBox3D_1), "%.18g %.18g", sEnvelope.MinX,
784 : sEnvelope.MinY);
785 0 : while ((pszComma = strchr(szBox3D_1, ',')) != nullptr)
786 0 : *pszComma = '.';
787 0 : CPLsnprintf(szBox3D_2, sizeof(szBox3D_2), "%.18g %.18g", sEnvelope.MaxX,
788 : sEnvelope.MaxY);
789 0 : while ((pszComma = strchr(szBox3D_2, ',')) != nullptr)
790 0 : *pszComma = '.';
791 : osWHERE.Printf("(%s && 'BOX3D(%s, %s)'::box3d)",
792 0 : OGRAMIGOCLOUDEscapeIdentifier(osGeomColumn).c_str(),
793 0 : szBox3D_1, szBox3D_2);
794 : }
795 :
796 0 : if (!osQuery.empty())
797 : {
798 0 : if (!osWHERE.empty())
799 0 : osWHERE += " AND ";
800 0 : osWHERE += osQuery;
801 : }
802 :
803 0 : if (osFIDColName.empty())
804 : {
805 0 : osBaseSQL = osSELECTWithoutWHERE;
806 0 : if (!osWHERE.empty())
807 : {
808 0 : osBaseSQL += " WHERE ";
809 0 : osBaseSQL += osWHERE;
810 : }
811 : }
812 0 : }
813 :
814 : /************************************************************************/
815 : /* GetFeature() */
816 : /************************************************************************/
817 :
818 0 : OGRFeature *OGRAmigoCloudTableLayer::GetFeature(GIntBig nFeatureId)
819 : {
820 :
821 0 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
822 0 : return nullptr;
823 0 : FlushDeferredInsert();
824 :
825 0 : GetLayerDefn();
826 :
827 0 : if (osFIDColName.empty())
828 0 : return OGRAmigoCloudLayer::GetFeature(nFeatureId);
829 :
830 0 : const auto it = mFIDs.find(nFeatureId);
831 0 : if (it != mFIDs.end())
832 : {
833 0 : const OGRAmigoCloudFID &aFID = it->second;
834 :
835 0 : CPLString osSQL = osSELECTWithoutWHERE;
836 0 : osSQL += " WHERE ";
837 0 : osSQL += OGRAMIGOCLOUDEscapeIdentifier(osFIDColName).c_str();
838 0 : osSQL += " = ";
839 0 : osSQL += CPLSPrintf("'%s'", aFID.osAmigoId.c_str());
840 :
841 0 : json_object *poObj = poDS->RunSQL(osSQL);
842 0 : json_object *poRowObj = OGRAMIGOCLOUDGetSingleRow(poObj);
843 0 : if (poRowObj == nullptr)
844 : {
845 0 : if (poObj != nullptr)
846 0 : json_object_put(poObj);
847 0 : return OGRAmigoCloudLayer::GetFeature(nFeatureId);
848 : }
849 :
850 0 : OGRFeature *poFeature = BuildFeature(poRowObj);
851 0 : json_object_put(poObj);
852 :
853 0 : return poFeature;
854 : }
855 0 : return nullptr;
856 : }
857 :
858 : /************************************************************************/
859 : /* GetFeatureCount() */
860 : /************************************************************************/
861 :
862 0 : GIntBig OGRAmigoCloudTableLayer::GetFeatureCount(int bForce)
863 : {
864 :
865 0 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
866 0 : return 0;
867 0 : FlushDeferredInsert();
868 :
869 0 : GetLayerDefn();
870 :
871 : CPLString osSQL(
872 : CPLSPrintf("SELECT COUNT(*) FROM %s",
873 0 : OGRAMIGOCLOUDEscapeIdentifier(osTableName).c_str()));
874 0 : if (!osWHERE.empty())
875 : {
876 0 : osSQL += " WHERE ";
877 0 : osSQL += osWHERE;
878 : }
879 :
880 0 : json_object *poObj = poDS->RunSQL(osSQL);
881 0 : json_object *poRowObj = OGRAMIGOCLOUDGetSingleRow(poObj);
882 0 : if (poRowObj == nullptr)
883 : {
884 0 : if (poObj != nullptr)
885 0 : json_object_put(poObj);
886 0 : return OGRAmigoCloudLayer::GetFeatureCount(bForce);
887 : }
888 :
889 0 : json_object *poCount = CPL_json_object_object_get(poRowObj, "count");
890 0 : if (poCount == nullptr || json_object_get_type(poCount) != json_type_int)
891 : {
892 0 : json_object_put(poObj);
893 0 : return OGRAmigoCloudLayer::GetFeatureCount(bForce);
894 : }
895 :
896 0 : GIntBig nRet = (GIntBig)json_object_get_int64(poCount);
897 :
898 0 : json_object_put(poObj);
899 :
900 0 : return nRet;
901 : }
902 :
903 : /************************************************************************/
904 : /* GetExtent() */
905 : /* */
906 : /* For PostGIS use internal Extend(geometry) function */
907 : /* in other cases we use standard OGRLayer::GetExtent() */
908 : /************************************************************************/
909 :
910 0 : OGRErr OGRAmigoCloudTableLayer::GetExtent(int iGeomField, OGREnvelope *psExtent,
911 : int bForce)
912 : {
913 0 : CPLString osSQL;
914 :
915 0 : if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
916 0 : return OGRERR_FAILURE;
917 0 : FlushDeferredInsert();
918 :
919 0 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
920 0 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
921 : {
922 0 : if (iGeomField != 0)
923 : {
924 0 : CPLError(CE_Failure, CPLE_AppDefined,
925 : "Invalid geometry field index : %d", iGeomField);
926 : }
927 0 : return OGRERR_FAILURE;
928 : }
929 :
930 : OGRGeomFieldDefn *poGeomFieldDefn =
931 0 : poFeatureDefn->GetGeomFieldDefn(iGeomField);
932 :
933 : /* Do not take the spatial filter into account */
934 : osSQL.Printf(
935 : "SELECT ST_Extent(%s) FROM %s",
936 0 : OGRAMIGOCLOUDEscapeIdentifier(poGeomFieldDefn->GetNameRef()).c_str(),
937 0 : OGRAMIGOCLOUDEscapeIdentifier(osTableName).c_str());
938 :
939 0 : json_object *poObj = poDS->RunSQL(osSQL);
940 0 : json_object *poRowObj = OGRAMIGOCLOUDGetSingleRow(poObj);
941 0 : if (poRowObj != nullptr)
942 : {
943 : json_object *poExtent =
944 0 : CPL_json_object_object_get(poRowObj, "st_extent");
945 0 : if (poExtent != nullptr &&
946 0 : json_object_get_type(poExtent) == json_type_string)
947 : {
948 0 : const char *pszBox = json_object_get_string(poExtent);
949 : const char *ptr, *ptrEndParenthesis;
950 : char szVals[64 * 6 + 6];
951 :
952 0 : ptr = strchr(pszBox, '(');
953 0 : if (ptr)
954 0 : ptr++;
955 0 : if (ptr == nullptr ||
956 0 : (ptrEndParenthesis = strchr(ptr, ')')) == nullptr ||
957 0 : ptrEndParenthesis - ptr > (int)(sizeof(szVals) - 1))
958 : {
959 0 : CPLError(CE_Failure, CPLE_IllegalArg,
960 : "Bad extent representation: '%s'", pszBox);
961 :
962 0 : json_object_put(poObj);
963 0 : return OGRERR_FAILURE;
964 : }
965 :
966 0 : strncpy(szVals, ptr, ptrEndParenthesis - ptr);
967 0 : szVals[ptrEndParenthesis - ptr] = '\0';
968 :
969 : char **papszTokens =
970 0 : CSLTokenizeString2(szVals, " ,", CSLT_HONOURSTRINGS);
971 0 : int nTokenCnt = 4;
972 :
973 0 : if (CSLCount(papszTokens) != nTokenCnt)
974 : {
975 0 : CPLError(CE_Failure, CPLE_IllegalArg,
976 : "Bad extent representation: '%s'", pszBox);
977 0 : CSLDestroy(papszTokens);
978 :
979 0 : json_object_put(poObj);
980 0 : return OGRERR_FAILURE;
981 : }
982 :
983 : // Take X,Y coords
984 : // For PostGIS ver >= 1.0.0 -> Tokens: X1 Y1 X2 Y2 (nTokenCnt = 4)
985 : // For PostGIS ver < 1.0.0 -> Tokens: X1 Y1 Z1 X2 Y2 Z2 (nTokenCnt =
986 : // 6)
987 : // => X2 index calculated as nTokenCnt/2
988 : // Y2 index calculated as nTokenCnt/2+1
989 :
990 0 : psExtent->MinX = CPLAtof(papszTokens[0]);
991 0 : psExtent->MinY = CPLAtof(papszTokens[1]);
992 0 : psExtent->MaxX = CPLAtof(papszTokens[nTokenCnt / 2]);
993 0 : psExtent->MaxY = CPLAtof(papszTokens[nTokenCnt / 2 + 1]);
994 :
995 0 : CSLDestroy(papszTokens);
996 :
997 0 : json_object_put(poObj);
998 0 : return OGRERR_NONE;
999 : }
1000 : }
1001 :
1002 0 : if (poObj != nullptr)
1003 0 : json_object_put(poObj);
1004 :
1005 0 : if (iGeomField == 0)
1006 0 : return OGRLayer::GetExtent(psExtent, bForce);
1007 : else
1008 0 : return OGRLayer::GetExtent(iGeomField, psExtent, bForce);
1009 : }
1010 :
1011 : /************************************************************************/
1012 : /* TestCapability() */
1013 : /************************************************************************/
1014 :
1015 0 : int OGRAmigoCloudTableLayer::TestCapability(const char *pszCap)
1016 :
1017 : {
1018 0 : if (EQUAL(pszCap, OLCFastFeatureCount))
1019 0 : return TRUE;
1020 0 : if (EQUAL(pszCap, OLCFastGetExtent))
1021 0 : return TRUE;
1022 0 : if (EQUAL(pszCap, OLCRandomRead))
1023 : {
1024 0 : GetLayerDefn();
1025 0 : return !osFIDColName.empty();
1026 : }
1027 :
1028 0 : if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite) ||
1029 0 : EQUAL(pszCap, OLCDeleteFeature) || EQUAL(pszCap, ODsCCreateLayer) ||
1030 0 : EQUAL(pszCap, ODsCDeleteLayer))
1031 : {
1032 0 : return poDS->IsReadWrite();
1033 : }
1034 :
1035 0 : return OGRAmigoCloudLayer::TestCapability(pszCap);
1036 : }
1037 :
1038 : /************************************************************************/
1039 : /* SetDeferredCreation() */
1040 : /************************************************************************/
1041 :
1042 0 : void OGRAmigoCloudTableLayer::SetDeferredCreation(OGRwkbGeometryType eGType,
1043 : OGRSpatialReference *poSRS,
1044 : int bGeomNullable)
1045 : {
1046 0 : bDeferredCreation = TRUE;
1047 0 : nNextFID = 1;
1048 0 : CPLAssert(poFeatureDefn == nullptr);
1049 0 : poFeatureDefn = new OGRFeatureDefn(osTableName);
1050 0 : poFeatureDefn->Reference();
1051 0 : poFeatureDefn->SetGeomType(wkbNone);
1052 0 : if (eGType == wkbPolygon)
1053 0 : eGType = wkbMultiPolygon;
1054 0 : else if (eGType == wkbPolygon25D)
1055 0 : eGType = wkbMultiPolygon25D;
1056 0 : if (eGType != wkbNone)
1057 : {
1058 : auto poFieldDefn = std::make_unique<OGRAmigoCloudGeomFieldDefn>(
1059 0 : "wkb_geometry", eGType);
1060 0 : poFieldDefn->SetNullable(bGeomNullable);
1061 0 : if (poSRS != nullptr)
1062 : {
1063 0 : poFieldDefn->nSRID = poDS->FetchSRSId(poSRS);
1064 0 : poFieldDefn->SetSpatialRef(poSRS);
1065 : }
1066 0 : poFeatureDefn->AddGeomFieldDefn(std::move(poFieldDefn));
1067 : }
1068 :
1069 : osBaseSQL.Printf("SELECT * FROM %s",
1070 0 : OGRAMIGOCLOUDEscapeIdentifier(osTableName).c_str());
1071 0 : }
1072 :
1073 0 : CPLString OGRAmigoCloudTableLayer::GetAmigoCloudType(const OGRFieldDefn &oField)
1074 : {
1075 : char szFieldType[256];
1076 :
1077 : /* -------------------------------------------------------------------- */
1078 : /* AmigoCloud supported types. */
1079 : /* -------------------------------------------------------------------- */
1080 0 : if (oField.GetType() == OFTInteger)
1081 : {
1082 0 : strcpy(szFieldType, "integer");
1083 : }
1084 0 : else if (oField.GetType() == OFTInteger64)
1085 : {
1086 0 : strcpy(szFieldType, "bigint");
1087 : }
1088 0 : else if (oField.GetType() == OFTReal)
1089 : {
1090 0 : strcpy(szFieldType, "float");
1091 : }
1092 0 : else if (oField.GetType() == OFTString)
1093 : {
1094 0 : strcpy(szFieldType, "string");
1095 : }
1096 0 : else if (oField.GetType() == OFTDate)
1097 : {
1098 0 : strcpy(szFieldType, "date");
1099 : }
1100 0 : else if (oField.GetType() == OFTTime)
1101 : {
1102 0 : strcpy(szFieldType, "time");
1103 : }
1104 0 : else if (oField.GetType() == OFTDateTime)
1105 : {
1106 0 : strcpy(szFieldType, "datetime");
1107 : }
1108 : else
1109 : {
1110 0 : CPLError(CE_Failure, CPLE_NotSupported,
1111 : "Can't create field %s with type %s on PostgreSQL layers.",
1112 : oField.GetNameRef(),
1113 : OGRFieldDefn::GetFieldTypeName(oField.GetType()));
1114 0 : strcpy(szFieldType, "");
1115 : }
1116 :
1117 0 : return szFieldType;
1118 : }
1119 :
1120 0 : bool OGRAmigoCloudTableLayer::IsDatasetExists()
1121 : {
1122 0 : std::stringstream url;
1123 0 : url << std::string(poDS->GetAPIURL())
1124 0 : << "/users/0/projects/" + std::string(poDS->GetProjectId()) +
1125 0 : "/datasets/" + osDatasetId;
1126 0 : json_object *result = poDS->RunGET(url.str().c_str());
1127 0 : if (result == nullptr)
1128 0 : return false;
1129 :
1130 : {
1131 0 : int type = json_object_get_type(result);
1132 0 : if (type == json_type_object)
1133 : {
1134 0 : json_object *poId = CPL_json_object_object_get(result, "id");
1135 0 : if (poId != nullptr)
1136 : {
1137 0 : json_object_put(result);
1138 0 : return true;
1139 : }
1140 : }
1141 0 : json_object_put(result);
1142 : }
1143 :
1144 : // Sleep 3 sec
1145 0 : CPLSleep(3);
1146 :
1147 0 : return false;
1148 : }
1149 :
1150 : /************************************************************************/
1151 : /* RunDeferredCreationIfNecessary() */
1152 : /************************************************************************/
1153 :
1154 0 : OGRErr OGRAmigoCloudTableLayer::RunDeferredCreationIfNecessary()
1155 : {
1156 0 : if (!bDeferredCreation)
1157 0 : return OGRERR_NONE;
1158 0 : bDeferredCreation = FALSE;
1159 0 : std::stringstream json;
1160 0 : json << "{ \"name\":\"" << osDatasetId << "\",";
1161 0 : json << "\"schema\": \"[";
1162 0 : int counter = 0;
1163 0 : OGRwkbGeometryType eGType = GetGeomType();
1164 0 : if (eGType != wkbNone)
1165 : {
1166 0 : CPLString osGeomType = OGRToOGCGeomType(eGType);
1167 0 : if (wkbHasZ(eGType))
1168 0 : osGeomType += "Z";
1169 :
1170 : OGRAmigoCloudGeomFieldDefn *poFieldDefn =
1171 0 : (OGRAmigoCloudGeomFieldDefn *)poFeatureDefn->GetGeomFieldDefn(0);
1172 :
1173 0 : json << "{\\\"name\\\":\\\"" << poFieldDefn->GetNameRef() << "\\\",";
1174 0 : json << "\\\"type\\\":\\\"geometry\\\",";
1175 0 : json << "\\\"geometry_type\\\":\\\"" << osGeomType << "\\\",";
1176 :
1177 0 : if (!poFieldDefn->IsNullable())
1178 0 : json << "\\\"nullable\\\":false,";
1179 : else
1180 0 : json << "\\\"nullable\\\":true,";
1181 :
1182 0 : json << "\\\"visible\\\": true}";
1183 :
1184 0 : counter++;
1185 : }
1186 :
1187 0 : for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
1188 : {
1189 0 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(i);
1190 0 : if (strcmp(poFieldDefn->GetNameRef(), osFIDColName) != 0)
1191 : {
1192 0 : if (counter > 0)
1193 0 : json << ",";
1194 :
1195 : json << "{\\\"name\\\":\\\"" << poFieldDefn->GetNameRef()
1196 0 : << "\\\",";
1197 0 : json << "\\\"type\\\":\\\"" << GetAmigoCloudType(*poFieldDefn)
1198 0 : << "\\\",";
1199 0 : if (!poFieldDefn->IsNullable())
1200 0 : json << "\\\"nullable\\\":false,";
1201 : else
1202 0 : json << "\\\"nullable\\\":true,";
1203 :
1204 0 : if (poFieldDefn->GetDefault() != nullptr &&
1205 0 : !poFieldDefn->IsDefaultDriverSpecific())
1206 : {
1207 : json << "\\\"default\\\":\\\"" << poFieldDefn->GetDefault()
1208 0 : << "\\\",";
1209 : }
1210 0 : json << "\\\"visible\\\": true}";
1211 0 : counter++;
1212 : }
1213 : }
1214 :
1215 0 : json << " ] \" }";
1216 :
1217 0 : std::stringstream url;
1218 0 : url << std::string(poDS->GetAPIURL())
1219 0 : << "/users/0/projects/" + std::string(poDS->GetProjectId()) +
1220 0 : "/datasets/create";
1221 :
1222 0 : json_object *result = poDS->RunPOST(url.str().c_str(), json.str().c_str());
1223 0 : if (result != nullptr)
1224 : {
1225 0 : if (json_object_get_type(result) == json_type_object)
1226 : {
1227 0 : json_object *poName = CPL_json_object_object_get(result, "name");
1228 0 : if (poName != nullptr)
1229 : {
1230 0 : osName = json_object_to_json_string(poName);
1231 : }
1232 :
1233 0 : json_object *poId = CPL_json_object_object_get(result, "id");
1234 0 : if (poId != nullptr)
1235 : {
1236 : osTableName =
1237 0 : CPLString("dataset_") + json_object_to_json_string(poId);
1238 0 : osDatasetId = json_object_to_json_string(poId);
1239 0 : int retry = 10;
1240 0 : while (!IsDatasetExists() && retry >= 0)
1241 : {
1242 0 : retry--;
1243 : }
1244 0 : json_object_put(result);
1245 0 : return OGRERR_NONE;
1246 : }
1247 : }
1248 : }
1249 0 : return OGRERR_FAILURE;
1250 : }
|