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

Generated by: LCOV version 1.14