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

Generated by: LCOV version 1.14