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

Generated by: LCOV version 1.14