LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/amigocloud - ogramigoclouddatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 430 0.0 %
Date: 2024-05-09 00:19:14 Functions: 0 26 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  AmigoCloud Translator
       4             :  * Purpose:  Implements OGRAmigoCloudDataSource class
       5             :  * Author:   Victor Chernetsky, <victor at amigocloud dot com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2015, Victor Chernetsky, <victor at amigocloud dot com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "ogr_amigocloud.h"
      30             : #include "ogr_pgdump.h"
      31             : #include "ogrgeojsonreader.h"
      32             : #include <sstream>
      33             : 
      34             : CPLString OGRAMIGOCLOUDGetOptionValue(const char *pszFilename,
      35             :                                       const char *pszOptionName);
      36             : 
      37             : /************************************************************************/
      38             : /*                        OGRAmigoCloudDataSource()                        */
      39             : /************************************************************************/
      40             : 
      41           0 : OGRAmigoCloudDataSource::OGRAmigoCloudDataSource()
      42             :     : pszName(nullptr), pszProjectId(nullptr), papoLayers(nullptr), nLayers(0),
      43             :       bReadWrite(false), bUseHTTPS(true), bMustCleanPersistent(false),
      44           0 :       bHasOGRMetadataFunction(-1)
      45             : {
      46           0 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                       ~OGRAmigoCloudDataSource()                        */
      50             : /************************************************************************/
      51             : 
      52           0 : OGRAmigoCloudDataSource::~OGRAmigoCloudDataSource()
      53             : 
      54             : {
      55           0 :     for (int i = 0; i < nLayers; i++)
      56           0 :         delete papoLayers[i];
      57           0 :     CPLFree(papoLayers);
      58             : 
      59           0 :     if (bMustCleanPersistent)
      60             :     {
      61           0 :         char **papszOptions = nullptr;
      62           0 :         papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT",
      63             :                                        CPLSPrintf("AMIGOCLOUD:%p", this));
      64           0 :         papszOptions = CSLAddString(papszOptions, GetUserAgentOption().c_str());
      65           0 :         CPLHTTPDestroyResult(CPLHTTPFetch(GetAPIURL(), papszOptions));
      66           0 :         CSLDestroy(papszOptions);
      67             :     }
      68             : 
      69           0 :     CPLFree(pszName);
      70           0 :     CPLFree(pszProjectId);
      71           0 : }
      72             : 
      73           0 : std::string OGRAmigoCloudDataSource::GetUserAgentOption()
      74             : {
      75           0 :     std::stringstream userAgent;
      76             :     userAgent << "USERAGENT=gdal/AmigoCloud build:"
      77           0 :               << GDALVersionInfo("RELEASE_NAME");
      78           0 :     return userAgent.str();
      79             : }
      80             : 
      81             : /************************************************************************/
      82             : /*                           TestCapability()                           */
      83             : /************************************************************************/
      84             : 
      85           0 : int OGRAmigoCloudDataSource::TestCapability(const char *pszCap)
      86             : 
      87             : {
      88           0 :     if (bReadWrite && EQUAL(pszCap, ODsCCreateLayer) && nLayers == 0)
      89           0 :         return TRUE;
      90           0 :     else if (bReadWrite && EQUAL(pszCap, ODsCDeleteLayer))
      91           0 :         return TRUE;
      92           0 :     else if (EQUAL(pszCap, ODsCRandomLayerWrite))
      93           0 :         return bReadWrite;
      94           0 :     else if (EQUAL(pszCap, ODsCZGeometries))
      95           0 :         return TRUE;
      96             :     else
      97           0 :         return FALSE;
      98             : }
      99             : 
     100             : /************************************************************************/
     101             : /*                              GetLayer()                              */
     102             : /************************************************************************/
     103             : 
     104           0 : OGRLayer *OGRAmigoCloudDataSource::GetLayer(int iLayer)
     105             : {
     106           0 :     if (iLayer < 0 || iLayer >= nLayers)
     107           0 :         return nullptr;
     108             :     else
     109           0 :         return papoLayers[iLayer];
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                          GetLayerByName()                            */
     114             : /************************************************************************/
     115             : 
     116           0 : OGRLayer *OGRAmigoCloudDataSource::GetLayerByName(const char *pszLayerName)
     117             : {
     118           0 :     if (nLayers > 1)
     119             :     {
     120           0 :         return OGRDataSource::GetLayerByName(pszLayerName);
     121             :     }
     122           0 :     else if (nLayers == 1)
     123             :     {
     124           0 :         return papoLayers[0];
     125             :     }
     126           0 :     return nullptr;
     127             : }
     128             : 
     129             : /************************************************************************/
     130             : /*                     OGRAMIGOCLOUDGetOptionValue()                       */
     131             : /************************************************************************/
     132             : 
     133           0 : CPLString OGRAMIGOCLOUDGetOptionValue(const char *pszFilename,
     134             :                                       const char *pszOptionName)
     135             : {
     136           0 :     CPLString osOptionName(pszOptionName);
     137           0 :     osOptionName += "=";
     138           0 :     const char *pszOptionValue = strstr(pszFilename, osOptionName);
     139           0 :     if (!pszOptionValue)
     140           0 :         return "";
     141             : 
     142           0 :     CPLString osOptionValue(pszOptionValue + osOptionName.size());
     143           0 :     const char *pszSpace = strchr(osOptionValue.c_str(), ' ');
     144           0 :     if (pszSpace)
     145           0 :         osOptionValue.resize(pszSpace - osOptionValue.c_str());
     146           0 :     return osOptionValue;
     147             : }
     148             : 
     149           0 : bool OGRAmigoCloudDataSource::ListDatasets()
     150             : {
     151           0 :     std::stringstream url;
     152           0 :     url << std::string(GetAPIURL()) << "/users/0/projects/"
     153           0 :         << std::string(GetProjectId()) << "/datasets/?summary";
     154           0 :     json_object *result = RunGET(url.str().c_str());
     155           0 :     if (result == nullptr)
     156             :     {
     157           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AmigoCloud:get failed.");
     158           0 :         return false;
     159             :     }
     160             : 
     161             :     {
     162           0 :         auto type = json_object_get_type(result);
     163           0 :         if (type == json_type_object)
     164             :         {
     165             :             json_object *poResults =
     166           0 :                 CPL_json_object_object_get(result, "results");
     167           0 :             if (poResults != nullptr &&
     168           0 :                 json_object_get_type(poResults) == json_type_array)
     169             :             {
     170           0 :                 CPLprintf("List of available datasets for project id: %s\n",
     171             :                           GetProjectId());
     172           0 :                 CPLprintf("| id \t | name\n");
     173           0 :                 CPLprintf("|--------|-------------------\n");
     174           0 :                 const auto nSize = json_object_array_length(poResults);
     175           0 :                 for (auto i = decltype(nSize){0}; i < nSize; ++i)
     176             :                 {
     177           0 :                     json_object *ds = json_object_array_get_idx(poResults, i);
     178           0 :                     if (ds != nullptr)
     179             :                     {
     180           0 :                         const char *name = nullptr;
     181           0 :                         int64_t dataset_id = 0;
     182             :                         json_object *poName =
     183           0 :                             CPL_json_object_object_get(ds, "name");
     184           0 :                         if (poName != nullptr)
     185             :                         {
     186           0 :                             name = json_object_get_string(poName);
     187             :                         }
     188             :                         json_object *poId =
     189           0 :                             CPL_json_object_object_get(ds, "id");
     190           0 :                         if (poId != nullptr)
     191             :                         {
     192           0 :                             dataset_id = json_object_get_int64(poId);
     193             :                         }
     194           0 :                         if (name != nullptr)
     195             :                         {
     196           0 :                             std::stringstream str;
     197           0 :                             str << "| " << dataset_id << "\t | " << name;
     198           0 :                             CPLprintf("%s\n", str.str().c_str());
     199             :                         }
     200             :                     }
     201             :                 }
     202             :             }
     203             :         }
     204           0 :         json_object_put(result);
     205             :     }
     206           0 :     return true;
     207             : }
     208             : 
     209             : /************************************************************************/
     210             : /*                                Open()                                */
     211             : /************************************************************************/
     212             : 
     213           0 : int OGRAmigoCloudDataSource::Open(const char *pszFilename,
     214             :                                   char **papszOpenOptionsIn, int bUpdateIn)
     215             : 
     216             : {
     217             : 
     218           0 :     bReadWrite = CPL_TO_BOOL(bUpdateIn);
     219             : 
     220           0 :     pszName = CPLStrdup(pszFilename);
     221           0 :     pszProjectId = CPLStrdup(pszFilename + strlen("AMIGOCLOUD:"));
     222           0 :     char *pchSpace = strchr(pszProjectId, ' ');
     223           0 :     if (pchSpace)
     224           0 :         *pchSpace = '\0';
     225           0 :     if (pszProjectId[0] == 0)
     226             :     {
     227           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Missing project id");
     228           0 :         return FALSE;
     229             :     }
     230             : 
     231             :     osAPIKey =
     232             :         CSLFetchNameValueDef(papszOpenOptionsIn, "AMIGOCLOUD_API_KEY",
     233           0 :                              CPLGetConfigOption("AMIGOCLOUD_API_KEY", ""));
     234             : 
     235           0 :     if (osAPIKey.empty())
     236             :     {
     237             :         osAPIKey =
     238           0 :             OGRAMIGOCLOUDGetOptionValue(pszFilename, "AMIGOCLOUD_API_KEY");
     239             :     }
     240           0 :     if (osAPIKey.empty())
     241             :     {
     242           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     243             :                  "AMIGOCLOUD_API_KEY is not defined.\n");
     244           0 :         return FALSE;
     245             :     }
     246             : 
     247           0 :     OGRLayer *poSchemaLayer = ExecuteSQLInternal("SELECT current_schema()");
     248           0 :     if (poSchemaLayer)
     249             :     {
     250           0 :         OGRFeature *poFeat = poSchemaLayer->GetNextFeature();
     251           0 :         if (poFeat)
     252             :         {
     253           0 :             if (poFeat->GetFieldCount() == 1)
     254             :             {
     255           0 :                 osCurrentSchema = poFeat->GetFieldAsString(0);
     256             :             }
     257           0 :             delete poFeat;
     258             :         }
     259           0 :         ReleaseResultSet(poSchemaLayer);
     260             :     }
     261           0 :     if (osCurrentSchema.empty())
     262           0 :         return FALSE;
     263             : 
     264           0 :     CPLString osDatasets = OGRAMIGOCLOUDGetOptionValue(pszFilename, "datasets");
     265           0 :     if (!osDatasets.empty())
     266             :     {
     267           0 :         char **papszTables = CSLTokenizeString2(osDatasets, ",", 0);
     268           0 :         for (int i = 0; papszTables && papszTables[i]; i++)
     269             :         {
     270             : 
     271           0 :             papoLayers = (OGRAmigoCloudTableLayer **)CPLRealloc(
     272           0 :                 papoLayers, (nLayers + 1) * sizeof(OGRAmigoCloudTableLayer *));
     273             : 
     274           0 :             papoLayers[nLayers++] =
     275           0 :                 new OGRAmigoCloudTableLayer(this, papszTables[i]);
     276             :         }
     277           0 :         CSLDestroy(papszTables);
     278             : 
     279             :         // If OVERWRITE: YES, truncate the layer.
     280           0 :         if (nLayers == 1 &&
     281           0 :             CPLFetchBool(papszOpenOptionsIn, "OVERWRITE", false))
     282             :         {
     283           0 :             TruncateDataset(papoLayers[0]->GetTableName());
     284             :         }
     285           0 :         return TRUE;
     286             :     }
     287             :     else
     288             :     {
     289             :         // If 'datasets' word is in the filename, but no dataset id specified,
     290             :         // print the list of available datasets
     291           0 :         if (std::string(pszFilename).find("datasets") != std::string::npos)
     292           0 :             ListDatasets();
     293             :     }
     294             : 
     295           0 :     return TRUE;
     296             : }
     297             : 
     298             : /************************************************************************/
     299             : /*                            GetAPIURL()                               */
     300             : /************************************************************************/
     301             : 
     302           0 : const char *OGRAmigoCloudDataSource::GetAPIURL() const
     303             : {
     304           0 :     const char *pszAPIURL = CPLGetConfigOption("AMIGOCLOUD_API_URL", nullptr);
     305           0 :     if (pszAPIURL)
     306           0 :         return pszAPIURL;
     307             : 
     308           0 :     else if (bUseHTTPS)
     309           0 :         return CPLSPrintf("https://app.amigocloud.com/api/v1");
     310             :     else
     311           0 :         return CPLSPrintf("http://app.amigocloud.com/api/v1");
     312             : }
     313             : 
     314             : /************************************************************************/
     315             : /*                             FetchSRSId()                             */
     316             : /************************************************************************/
     317             : 
     318           0 : int OGRAmigoCloudDataSource::FetchSRSId(OGRSpatialReference *poSRS)
     319             : 
     320             : {
     321           0 :     if (poSRS == nullptr)
     322           0 :         return 0;
     323             : 
     324           0 :     OGRSpatialReference oSRS(*poSRS);
     325             :     // cppcheck-suppress uselessAssignmentPtrArg
     326           0 :     poSRS = nullptr;
     327             : 
     328           0 :     const char *pszAuthorityName = oSRS.GetAuthorityName(nullptr);
     329             : 
     330           0 :     if (pszAuthorityName == nullptr || strlen(pszAuthorityName) == 0)
     331             :     {
     332             :         /* --------------------------------------------------------------------
     333             :          */
     334             :         /*      Try to identify an EPSG code */
     335             :         /* --------------------------------------------------------------------
     336             :          */
     337           0 :         oSRS.AutoIdentifyEPSG();
     338             : 
     339           0 :         pszAuthorityName = oSRS.GetAuthorityName(nullptr);
     340           0 :         if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG"))
     341             :         {
     342           0 :             const char *pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
     343           0 :             if (pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
     344             :             {
     345             :                 /* Import 'clean' SRS */
     346           0 :                 oSRS.importFromEPSG(atoi(pszAuthorityCode));
     347             : 
     348           0 :                 pszAuthorityName = oSRS.GetAuthorityName(nullptr);
     349             :             }
     350             :         }
     351             :     }
     352             :     /* -------------------------------------------------------------------- */
     353             :     /*      Check whether the EPSG authority code is already mapped to a    */
     354             :     /*      SRS ID.                                                         */
     355             :     /* -------------------------------------------------------------------- */
     356           0 :     if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG"))
     357             :     {
     358             :         /* For the root authority name 'EPSG', the authority code
     359             :          * should always be integral
     360             :          */
     361           0 :         const int nAuthorityCode = atoi(oSRS.GetAuthorityCode(nullptr));
     362             : 
     363           0 :         return nAuthorityCode;
     364             :     }
     365             : 
     366           0 :     return 0;
     367             : }
     368             : 
     369             : /************************************************************************/
     370             : /*                          ICreateLayer()                              */
     371             : /************************************************************************/
     372             : 
     373             : OGRLayer *
     374           0 : OGRAmigoCloudDataSource::ICreateLayer(const char *pszNameIn,
     375             :                                       const OGRGeomFieldDefn *poGeomFieldDefn,
     376             :                                       CSLConstList papszOptions)
     377             : {
     378           0 :     if (!bReadWrite)
     379             :     {
     380           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     381             :                  "Operation not available in read-only mode");
     382           0 :         return nullptr;
     383             :     }
     384             : 
     385           0 :     const auto eGType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
     386             :     const auto poSpatialRef =
     387           0 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
     388             : 
     389           0 :     CPLString osName(pszNameIn);
     390             :     OGRAmigoCloudTableLayer *poLayer =
     391           0 :         new OGRAmigoCloudTableLayer(this, osName);
     392             :     const bool bGeomNullable =
     393           0 :         CPLFetchBool(papszOptions, "GEOMETRY_NULLABLE", true);
     394           0 :     OGRSpatialReference *poSRSClone = nullptr;
     395           0 :     if (poSpatialRef)
     396             :     {
     397           0 :         poSRSClone = poSpatialRef->Clone();
     398           0 :         poSRSClone->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     399             :     }
     400           0 :     poLayer->SetDeferredCreation(eGType, poSRSClone, bGeomNullable);
     401           0 :     if (poSRSClone)
     402           0 :         poSRSClone->Release();
     403           0 :     papoLayers = (OGRAmigoCloudTableLayer **)CPLRealloc(
     404           0 :         papoLayers, (nLayers + 1) * sizeof(OGRAmigoCloudTableLayer *));
     405           0 :     papoLayers[nLayers++] = poLayer;
     406             : 
     407           0 :     return poLayer;
     408             : }
     409             : 
     410             : /************************************************************************/
     411             : /*                            DeleteLayer()                             */
     412             : /************************************************************************/
     413             : 
     414           0 : OGRErr OGRAmigoCloudDataSource::DeleteLayer(int iLayer)
     415             : {
     416           0 :     if (!bReadWrite)
     417             :     {
     418           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     419             :                  "Operation not available in read-only mode");
     420           0 :         return OGRERR_FAILURE;
     421             :     }
     422             : 
     423           0 :     if (iLayer < 0 || iLayer >= nLayers)
     424             :     {
     425           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     426             :                  "Layer %d not in legal range of 0 to %d.", iLayer,
     427           0 :                  nLayers - 1);
     428           0 :         return OGRERR_FAILURE;
     429             :     }
     430             : 
     431             :     /* -------------------------------------------------------------------- */
     432             :     /*      Blow away our OGR structures related to the layer.  This is     */
     433             :     /*      pretty dangerous if anything has a reference to this layer!     */
     434             :     /* -------------------------------------------------------------------- */
     435           0 :     CPLString osDatasetId = papoLayers[iLayer]->GetDatasetId();
     436             : 
     437           0 :     CPLDebug("AMIGOCLOUD", "DeleteLayer(%s)", osDatasetId.c_str());
     438             : 
     439           0 :     int bDeferredCreation = papoLayers[iLayer]->GetDeferredCreation();
     440           0 :     papoLayers[iLayer]->CancelDeferredCreation();
     441           0 :     delete papoLayers[iLayer];
     442           0 :     memmove(papoLayers + iLayer, papoLayers + iLayer + 1,
     443           0 :             sizeof(void *) * (nLayers - iLayer - 1));
     444           0 :     nLayers--;
     445             : 
     446           0 :     if (osDatasetId.empty())
     447           0 :         return OGRERR_NONE;
     448             : 
     449           0 :     if (!bDeferredCreation)
     450             :     {
     451           0 :         std::stringstream url;
     452           0 :         url << std::string(GetAPIURL())
     453           0 :             << "/users/0/projects/" + std::string(GetProjectId()) +
     454           0 :                    "/datasets/" + osDatasetId.c_str();
     455           0 :         if (!RunDELETE(url.str().c_str()))
     456             :         {
     457           0 :             return OGRERR_FAILURE;
     458             :         }
     459             :     }
     460             : 
     461           0 :     return OGRERR_NONE;
     462             : }
     463             : 
     464             : /************************************************************************/
     465             : /*                          AddHTTPOptions()                            */
     466             : /************************************************************************/
     467             : 
     468           0 : char **OGRAmigoCloudDataSource::AddHTTPOptions()
     469             : {
     470           0 :     bMustCleanPersistent = true;
     471             : 
     472           0 :     return CSLAddString(nullptr, CPLSPrintf("PERSISTENT=AMIGOCLOUD:%p", this));
     473             : }
     474             : 
     475             : /************************************************************************/
     476             : /*                               RunPOST()                               */
     477             : /************************************************************************/
     478             : 
     479           0 : json_object *OGRAmigoCloudDataSource::RunPOST(const char *pszURL,
     480             :                                               const char *pszPostData,
     481             :                                               const char *pszHeaders)
     482             : {
     483           0 :     CPLString osURL(pszURL);
     484             : 
     485             :     /* -------------------------------------------------------------------- */
     486             :     /*      Provide the API Key                                             */
     487             :     /* -------------------------------------------------------------------- */
     488           0 :     if (!osAPIKey.empty())
     489             :     {
     490           0 :         if (osURL.find("?") == std::string::npos)
     491           0 :             osURL += "?token=";
     492             :         else
     493           0 :             osURL += "&token=";
     494           0 :         osURL += osAPIKey;
     495             :     }
     496             : 
     497           0 :     char **papszOptions = nullptr;
     498           0 :     CPLString osPOSTFIELDS("POSTFIELDS=");
     499           0 :     if (pszPostData)
     500           0 :         osPOSTFIELDS += pszPostData;
     501           0 :     papszOptions = CSLAddString(papszOptions, osPOSTFIELDS);
     502           0 :     papszOptions = CSLAddString(papszOptions, pszHeaders);
     503           0 :     papszOptions = CSLAddString(papszOptions, GetUserAgentOption().c_str());
     504             : 
     505           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(osURL.c_str(), papszOptions);
     506           0 :     CSLDestroy(papszOptions);
     507           0 :     if (psResult == nullptr)
     508           0 :         return nullptr;
     509             : 
     510           0 :     if (psResult->pszContentType &&
     511           0 :         strncmp(psResult->pszContentType, "text/html", 9) == 0)
     512             :     {
     513           0 :         CPLDebug("AMIGOCLOUD", "RunPOST HTML Response: %s", psResult->pabyData);
     514           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     515             :                  "HTML error page returned by server: %s", psResult->pabyData);
     516           0 :         CPLHTTPDestroyResult(psResult);
     517           0 :         return nullptr;
     518             :     }
     519           0 :     if (psResult->pszErrBuf != nullptr && psResult->pabyData != nullptr)
     520             :     {
     521           0 :         CPLError(CE_Failure, CPLE_AppDefined, "POST Response: %s",
     522             :                  psResult->pabyData);
     523             :     }
     524           0 :     else if (psResult->nStatus != 0)
     525             :     {
     526           0 :         CPLDebug("AMIGOCLOUD", "RunPOST Error Status:%d", psResult->nStatus);
     527             :     }
     528             : 
     529           0 :     if (psResult->pabyData == nullptr)
     530             :     {
     531           0 :         CPLHTTPDestroyResult(psResult);
     532           0 :         return nullptr;
     533             :     }
     534             : 
     535           0 :     json_object *poObj = nullptr;
     536           0 :     const char *pszText = reinterpret_cast<const char *>(psResult->pabyData);
     537           0 :     if (!OGRJSonParse(pszText, &poObj, true))
     538             :     {
     539           0 :         CPLHTTPDestroyResult(psResult);
     540           0 :         return nullptr;
     541             :     }
     542             : 
     543           0 :     CPLHTTPDestroyResult(psResult);
     544             : 
     545           0 :     if (poObj != nullptr)
     546             :     {
     547           0 :         if (json_object_get_type(poObj) == json_type_object)
     548             :         {
     549           0 :             json_object *poError = CPL_json_object_object_get(poObj, "error");
     550           0 :             if (poError != nullptr &&
     551           0 :                 json_object_get_type(poError) == json_type_array &&
     552           0 :                 json_object_array_length(poError) > 0)
     553             :             {
     554           0 :                 poError = json_object_array_get_idx(poError, 0);
     555           0 :                 if (poError != nullptr &&
     556           0 :                     json_object_get_type(poError) == json_type_string)
     557             :                 {
     558           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     559             :                              "Error returned by server : %s",
     560             :                              json_object_get_string(poError));
     561           0 :                     json_object_put(poObj);
     562           0 :                     return nullptr;
     563             :                 }
     564             :             }
     565           0 :             json_object *poJob = CPL_json_object_object_get(poObj, "job");
     566           0 :             if (poJob != nullptr)
     567             :             {
     568           0 :                 const char *job = json_object_get_string(poJob);
     569           0 :                 if (job != nullptr)
     570             :                 {
     571           0 :                     waitForJobToFinish(job);
     572             :                 }
     573             :             }
     574             :         }
     575             :         else
     576             :         {
     577           0 :             json_object_put(poObj);
     578           0 :             return nullptr;
     579             :         }
     580             :     }
     581             : 
     582           0 :     return poObj;
     583             : }
     584             : 
     585           0 : bool OGRAmigoCloudDataSource::waitForJobToFinish(const char *jobId)
     586             : {
     587           0 :     std::stringstream url;
     588           0 :     url << std::string(GetAPIURL()) << "/me/jobs/" << std::string(jobId);
     589           0 :     int count = 0;
     590           0 :     while (count < 5)
     591             :     {
     592           0 :         count++;
     593           0 :         json_object *result = RunGET(url.str().c_str());
     594           0 :         if (result == nullptr)
     595             :         {
     596           0 :             CPLError(CE_Failure, CPLE_AppDefined, "waitForJobToFinish failed.");
     597           0 :             return false;
     598             :         }
     599             : 
     600             :         {
     601           0 :             int type = json_object_get_type(result);
     602           0 :             if (type == json_type_object)
     603             :             {
     604             :                 json_object *poStatus =
     605           0 :                     CPL_json_object_object_get(result, "status");
     606           0 :                 const char *status = json_object_get_string(poStatus);
     607           0 :                 if (status != nullptr)
     608             :                 {
     609           0 :                     if (std::string(status) == "SUCCESS")
     610             :                     {
     611           0 :                         return true;
     612             :                     }
     613           0 :                     else if (std::string(status) == "FAILURE")
     614             :                     {
     615           0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Job failed : %s",
     616             :                                  json_object_get_string(result));
     617           0 :                         return false;
     618             :                     }
     619             :                 }
     620             :             }
     621             :         }
     622           0 :         CPLSleep(1.0);  // Sleep 1 sec.
     623             :     }
     624           0 :     return false;
     625             : }
     626             : 
     627           0 : bool OGRAmigoCloudDataSource::TruncateDataset(const CPLString &tableName)
     628             : {
     629           0 :     std::stringstream changeset;
     630           0 :     changeset << "[{\"type\":\"DML\",\"entity\":\"" << tableName << "\",";
     631           0 :     changeset << "\"parent\":null,\"action\":\"TRUNCATE\",\"data\":null}]";
     632           0 :     SubmitChangeset(changeset.str());
     633           0 :     return true;
     634             : }
     635             : 
     636           0 : void OGRAmigoCloudDataSource::SubmitChangeset(const CPLString &json)
     637             : {
     638           0 :     std::stringstream url;
     639           0 :     url << std::string(GetAPIURL())
     640           0 :         << "/users/0/projects/" + std::string(GetProjectId()) +
     641           0 :                "/submit_changeset";
     642           0 :     std::stringstream changeset;
     643           0 :     changeset << "{\"changeset\":\"" << OGRAMIGOCLOUDJsonEncode(json) << "\"}";
     644           0 :     json_object *poObj = RunPOST(url.str().c_str(), changeset.str().c_str());
     645           0 :     if (poObj != nullptr)
     646           0 :         json_object_put(poObj);
     647           0 : }
     648             : 
     649             : /************************************************************************/
     650             : /*                               RunDELETE()                               */
     651             : /************************************************************************/
     652             : 
     653           0 : bool OGRAmigoCloudDataSource::RunDELETE(const char *pszURL)
     654             : {
     655           0 :     CPLString osURL(pszURL);
     656             : 
     657             :     /* -------------------------------------------------------------------- */
     658             :     /*      Provide the API Key                                             */
     659             :     /* -------------------------------------------------------------------- */
     660           0 :     if (!osAPIKey.empty())
     661             :     {
     662           0 :         if (osURL.find("?") == std::string::npos)
     663           0 :             osURL += "?token=";
     664             :         else
     665           0 :             osURL += "&token=";
     666           0 :         osURL += osAPIKey;
     667             :     }
     668             : 
     669           0 :     char **papszOptions = nullptr;
     670           0 :     CPLString osPOSTFIELDS("CUSTOMREQUEST=DELETE");
     671           0 :     papszOptions = CSLAddString(papszOptions, osPOSTFIELDS);
     672           0 :     papszOptions = CSLAddString(papszOptions, GetUserAgentOption().c_str());
     673             : 
     674           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(osURL.c_str(), papszOptions);
     675           0 :     CSLDestroy(papszOptions);
     676           0 :     if (psResult == nullptr)
     677           0 :         return false;
     678             : 
     679           0 :     if (psResult->pszContentType &&
     680           0 :         strncmp(psResult->pszContentType, "text/html", 9) == 0)
     681             :     {
     682           0 :         CPLDebug("AMIGOCLOUD", "RunDELETE HTML Response:%s",
     683             :                  psResult->pabyData);
     684           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     685             :                  "HTML error page returned by server:%s", psResult->pabyData);
     686           0 :         CPLHTTPDestroyResult(psResult);
     687           0 :         return false;
     688             :     }
     689           0 :     if (psResult->pszErrBuf != nullptr && psResult->pabyData != nullptr)
     690             :     {
     691           0 :         CPLError(CE_Failure, CPLE_AppDefined, "DELETE Response: %s",
     692             :                  psResult->pabyData);
     693             :     }
     694           0 :     else if (psResult->nStatus != 0)
     695             :     {
     696           0 :         CPLDebug("AMIGOCLOUD", "DELETE Error Status:%d", psResult->nStatus);
     697             :     }
     698           0 :     CPLHTTPDestroyResult(psResult);
     699             : 
     700           0 :     return true;
     701             : }
     702             : 
     703             : /************************************************************************/
     704             : /*                               RunGET()                               */
     705             : /************************************************************************/
     706             : 
     707           0 : json_object *OGRAmigoCloudDataSource::RunGET(const char *pszURL)
     708             : {
     709           0 :     CPLString osURL(pszURL);
     710             : 
     711             :     /* -------------------------------------------------------------------- */
     712             :     /*      Provide the API Key                                             */
     713             :     /* -------------------------------------------------------------------- */
     714           0 :     if (!osAPIKey.empty())
     715             :     {
     716           0 :         if (osURL.find("?") == std::string::npos)
     717           0 :             osURL += "?token=";
     718             :         else
     719           0 :             osURL += "&token=";
     720           0 :         osURL += osAPIKey;
     721             :     }
     722           0 :     char **papszOptions = nullptr;
     723           0 :     papszOptions = CSLAddString(papszOptions, GetUserAgentOption().c_str());
     724             : 
     725           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(osURL.c_str(), papszOptions);
     726           0 :     CSLDestroy(papszOptions);
     727           0 :     if (psResult == nullptr)
     728             :     {
     729           0 :         return nullptr;
     730             :     }
     731             : 
     732           0 :     if (psResult->pszContentType &&
     733           0 :         strncmp(psResult->pszContentType, "text/html", 9) == 0)
     734             :     {
     735           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     736             :                  "HTML error page returned by server:%s", psResult->pabyData);
     737           0 :         CPLHTTPDestroyResult(psResult);
     738           0 :         return nullptr;
     739             :     }
     740           0 :     if (psResult->pszErrBuf != nullptr && psResult->pabyData != nullptr)
     741             :     {
     742           0 :         CPLError(CE_Failure, CPLE_AppDefined, "GET Response: %s",
     743             :                  psResult->pabyData);
     744             :     }
     745           0 :     else if (psResult->nStatus != 0)
     746             :     {
     747           0 :         CPLDebug("AMIGOCLOUD", "RunGET Error Status:%d", psResult->nStatus);
     748             :     }
     749             : 
     750           0 :     if (psResult->pabyData == nullptr)
     751             :     {
     752           0 :         CPLHTTPDestroyResult(psResult);
     753           0 :         return nullptr;
     754             :     }
     755             : 
     756           0 :     CPLDebug("AMIGOCLOUD", "RunGET Response:%s", psResult->pabyData);
     757             : 
     758           0 :     json_object *poObj = nullptr;
     759           0 :     const char *pszText = reinterpret_cast<const char *>(psResult->pabyData);
     760           0 :     if (!OGRJSonParse(pszText, &poObj, true))
     761             :     {
     762           0 :         CPLHTTPDestroyResult(psResult);
     763           0 :         return nullptr;
     764             :     }
     765             : 
     766           0 :     CPLHTTPDestroyResult(psResult);
     767             : 
     768           0 :     if (poObj != nullptr)
     769             :     {
     770           0 :         if (json_object_get_type(poObj) == json_type_object)
     771             :         {
     772           0 :             json_object *poError = CPL_json_object_object_get(poObj, "error");
     773           0 :             if (poError != nullptr &&
     774           0 :                 json_object_get_type(poError) == json_type_array &&
     775           0 :                 json_object_array_length(poError) > 0)
     776             :             {
     777           0 :                 poError = json_object_array_get_idx(poError, 0);
     778           0 :                 if (poError != nullptr &&
     779           0 :                     json_object_get_type(poError) == json_type_string)
     780             :                 {
     781           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     782             :                              "Error returned by server : %s",
     783             :                              json_object_get_string(poError));
     784           0 :                     json_object_put(poObj);
     785           0 :                     return nullptr;
     786             :                 }
     787             :             }
     788             :         }
     789             :         else
     790             :         {
     791           0 :             json_object_put(poObj);
     792           0 :             return nullptr;
     793             :         }
     794             :     }
     795             : 
     796           0 :     return poObj;
     797             : }
     798             : 
     799             : /************************************************************************/
     800             : /*                               RunSQL()                               */
     801             : /************************************************************************/
     802             : 
     803           0 : json_object *OGRAmigoCloudDataSource::RunSQL(const char *pszUnescapedSQL)
     804             : {
     805           0 :     CPLString osSQL;
     806           0 :     std::string pszAPIURL = GetAPIURL();
     807           0 :     osSQL = pszAPIURL + "/users/0/projects/" + CPLString(pszProjectId) + "/sql";
     808           0 :     std::string sql = pszUnescapedSQL;
     809           0 :     if (sql.find("DELETE") != std::string::npos ||
     810           0 :         sql.find("delete") != std::string::npos ||
     811           0 :         sql.find("INSERT") != std::string::npos ||
     812           0 :         sql.find("insert") != std::string::npos ||
     813           0 :         sql.find("UPDATE") != std::string::npos ||
     814           0 :         sql.find("update") != std::string::npos)
     815             :     {
     816           0 :         std::stringstream query;
     817           0 :         query << "{\"query\": \"" << OGRAMIGOCLOUDJsonEncode(pszUnescapedSQL)
     818           0 :               << "\"}";
     819           0 :         return RunPOST(osSQL.c_str(), query.str().c_str());
     820             :     }
     821             :     else
     822             :     {
     823           0 :         osSQL += "?query=";
     824           0 :         char *pszEscaped = CPLEscapeString(pszUnescapedSQL, -1, CPLES_URL);
     825           0 :         osSQL += pszEscaped;
     826           0 :         CPLFree(pszEscaped);
     827           0 :         return RunGET(osSQL.c_str());
     828             :     }
     829             : }
     830             : 
     831             : /************************************************************************/
     832             : /*                        OGRAMIGOCLOUDGetSingleRow()                      */
     833             : /************************************************************************/
     834             : 
     835           0 : json_object *OGRAMIGOCLOUDGetSingleRow(json_object *poObj)
     836             : {
     837           0 :     if (poObj == nullptr)
     838             :     {
     839           0 :         return nullptr;
     840             :     }
     841             : 
     842           0 :     json_object *poRows = CPL_json_object_object_get(poObj, "data");
     843           0 :     if (poRows == nullptr || json_object_get_type(poRows) != json_type_array ||
     844           0 :         json_object_array_length(poRows) != 1)
     845             :     {
     846           0 :         return nullptr;
     847             :     }
     848             : 
     849           0 :     json_object *poRowObj = json_object_array_get_idx(poRows, 0);
     850           0 :     if (poRowObj == nullptr ||
     851           0 :         json_object_get_type(poRowObj) != json_type_object)
     852             :     {
     853           0 :         return nullptr;
     854             :     }
     855             : 
     856           0 :     return poRowObj;
     857             : }
     858             : 
     859             : /************************************************************************/
     860             : /*                             ExecuteSQL()                             */
     861             : /************************************************************************/
     862             : 
     863           0 : OGRLayer *OGRAmigoCloudDataSource::ExecuteSQL(const char *pszSQLCommand,
     864             :                                               OGRGeometry *poSpatialFilter,
     865             :                                               const char *pszDialect)
     866             : 
     867             : {
     868             :     /* -------------------------------------------------------------------- */
     869             :     /*      Use generic implementation for recognized dialects              */
     870             :     /* -------------------------------------------------------------------- */
     871           0 :     if (IsGenericSQLDialect(pszDialect))
     872           0 :         return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter,
     873           0 :                                        pszDialect);
     874             : 
     875           0 :     return ExecuteSQLInternal(pszSQLCommand, poSpatialFilter, pszDialect, true);
     876             : }
     877             : 
     878           0 : OGRLayer *OGRAmigoCloudDataSource::ExecuteSQLInternal(
     879             :     const char *pszSQLCommand, OGRGeometry *poSpatialFilter, const char *,
     880             :     bool bRunDeferredActions)
     881             : 
     882             : {
     883           0 :     if (bRunDeferredActions)
     884             :     {
     885           0 :         for (int iLayer = 0; iLayer < nLayers; iLayer++)
     886             :         {
     887           0 :             papoLayers[iLayer]->RunDeferredCreationIfNecessary();
     888           0 :             papoLayers[iLayer]->FlushDeferredInsert();
     889             :         }
     890             :     }
     891             : 
     892             :     /* Skip leading spaces */
     893           0 :     while (*pszSQLCommand == ' ')
     894           0 :         pszSQLCommand++;
     895             : 
     896           0 :     if (!EQUALN(pszSQLCommand, "SELECT", strlen("SELECT")) &&
     897           0 :         !EQUALN(pszSQLCommand, "EXPLAIN", strlen("EXPLAIN")) &&
     898           0 :         !EQUALN(pszSQLCommand, "WITH", strlen("WITH")))
     899             :     {
     900           0 :         RunSQL(pszSQLCommand);
     901           0 :         return nullptr;
     902             :     }
     903             : 
     904             :     OGRAmigoCloudResultLayer *poLayer =
     905           0 :         new OGRAmigoCloudResultLayer(this, pszSQLCommand);
     906             : 
     907           0 :     if (poSpatialFilter != nullptr)
     908           0 :         poLayer->SetSpatialFilter(poSpatialFilter);
     909             : 
     910           0 :     if (!poLayer->IsOK())
     911             :     {
     912           0 :         delete poLayer;
     913           0 :         return nullptr;
     914             :     }
     915             : 
     916           0 :     return poLayer;
     917             : }
     918             : 
     919             : /************************************************************************/
     920             : /*                          ReleaseResultSet()                          */
     921             : /************************************************************************/
     922             : 
     923           0 : void OGRAmigoCloudDataSource::ReleaseResultSet(OGRLayer *poLayer)
     924             : 
     925             : {
     926           0 :     delete poLayer;
     927           0 : }

Generated by: LCOV version 1.14