LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/amigocloud - ogramigocloudtablelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 612 0.0 %
Date: 2026-02-12 23:49:34 Functions: 0 25 0.0 %

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

Generated by: LCOV version 1.14