LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/couchdb - ogrcouchdbdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 541 272 50.3 %
Date: 2012-12-26 Functions: 33 21 63.6 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrcouchdbdatasource.cpp 25311 2012-12-15 12:48:14Z rouault $
       3                 :  *
       4                 :  * Project:  CouchDB Translator
       5                 :  * Purpose:  Implements OGRCouchDBDataSource class
       6                 :  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2011, Even Rouault <even dot rouault at mines dash paris dot org>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogr_couchdb.h"
      31                 : #include "swq.h"
      32                 : 
      33                 : CPL_CVSID("$Id: ogrcouchdbdatasource.cpp 25311 2012-12-15 12:48:14Z rouault $");
      34                 : 
      35                 : /************************************************************************/
      36                 : /*                        OGRCouchDBDataSource()                        */
      37                 : /************************************************************************/
      38                 : 
      39              96 : OGRCouchDBDataSource::OGRCouchDBDataSource()
      40                 : 
      41                 : {
      42              96 :     papoLayers = NULL;
      43              96 :     nLayers = 0;
      44                 : 
      45              96 :     pszName = NULL;
      46                 : 
      47              96 :     bReadWrite = FALSE;
      48                 : 
      49              96 :     bMustCleanPersistant = FALSE;
      50              96 : }
      51                 : 
      52                 : /************************************************************************/
      53                 : /*                       ~OGRCouchDBDataSource()                        */
      54                 : /************************************************************************/
      55                 : 
      56              96 : OGRCouchDBDataSource::~OGRCouchDBDataSource()
      57                 : 
      58                 : {
      59             112 :     for( int i = 0; i < nLayers; i++ )
      60              16 :         delete papoLayers[i];
      61              96 :     CPLFree( papoLayers );
      62                 : 
      63              96 :     if (bMustCleanPersistant)
      64                 :     {
      65                 :         char** papszOptions = CSLAddString(NULL,
      66              16 :                           CPLSPrintf("CLOSE_PERSISTENT=CouchDB:%p", this));
      67              16 :         CPLHTTPFetch( osURL, papszOptions);
      68              16 :         CSLDestroy(papszOptions);
      69                 :     }
      70                 : 
      71              96 :     CPLFree( pszName );
      72              96 : }
      73                 : 
      74                 : /************************************************************************/
      75                 : /*                           TestCapability()                           */
      76                 : /************************************************************************/
      77                 : 
      78               0 : int OGRCouchDBDataSource::TestCapability( const char * pszCap )
      79                 : 
      80                 : {
      81               0 :     if( bReadWrite && EQUAL(pszCap,ODsCCreateLayer) )
      82               0 :         return TRUE;
      83               0 :     else if( bReadWrite && EQUAL(pszCap,ODsCDeleteLayer) )
      84               0 :         return TRUE;
      85                 :     else
      86               0 :         return FALSE;
      87                 : }
      88                 : 
      89                 : /************************************************************************/
      90                 : /*                              GetLayer()                              */
      91                 : /************************************************************************/
      92                 : 
      93              17 : OGRLayer *OGRCouchDBDataSource::GetLayer( int iLayer )
      94                 : 
      95                 : {
      96              17 :     if( iLayer < 0 || iLayer >= nLayers )
      97               0 :         return NULL;
      98                 :     else
      99              17 :         return papoLayers[iLayer];
     100                 : }
     101                 : 
     102                 : /************************************************************************/
     103                 : /*                          GetLayerByName()                            */
     104                 : /************************************************************************/
     105                 : 
     106               1 : OGRLayer *OGRCouchDBDataSource::GetLayerByName(const char * pszLayerName)
     107                 : {
     108               1 :     OGRLayer* poLayer = OGRDataSource::GetLayerByName(pszLayerName);
     109               1 :     if (poLayer)
     110               1 :         return poLayer;
     111                 : 
     112               0 :     return OpenDatabase(pszLayerName);
     113                 : }
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                             OpenDatabase()                           */
     117                 : /************************************************************************/
     118                 : 
     119              15 : OGRLayer* OGRCouchDBDataSource::OpenDatabase(const char* pszLayerName)
     120                 : {
     121              15 :     CPLString osTableName;
     122              15 :     CPLString osEscapedName;
     123              15 :     if (pszLayerName)
     124                 :     {
     125               0 :         osTableName = pszLayerName;
     126               0 :         char* pszEscapedName = CPLEscapeString(pszLayerName, -1, CPLES_URL);
     127               0 :         osEscapedName = pszEscapedName;
     128               0 :         CPLFree(pszEscapedName);
     129                 :     }
     130                 :     else
     131                 :     {
     132              15 :         char* pszURL = CPLStrdup(osURL);
     133              15 :         char* pszLastSlash = strrchr(pszURL, '/');
     134              15 :         if (pszLastSlash)
     135                 :         {
     136              15 :             osEscapedName = pszLastSlash + 1;
     137              15 :             char* pszName = CPLUnescapeString(osEscapedName, NULL, CPLES_URL);
     138              15 :             osTableName = pszName;
     139              15 :             CPLFree(pszName);
     140              15 :             *pszLastSlash = 0;
     141                 :         }
     142              15 :         osURL = pszURL;
     143              15 :         CPLFree(pszURL);
     144              15 :         pszURL = NULL;
     145                 : 
     146              15 :         if (pszLastSlash == NULL)
     147               0 :             return NULL;
     148                 :     }
     149                 : 
     150              15 :     CPLString osURI("/");
     151              15 :     osURI += osEscapedName;
     152                 : 
     153              15 :     json_object* poAnswerObj = GET(osURI);
     154              15 :     if (poAnswerObj == NULL)
     155               0 :         return NULL;
     156                 : 
     157              15 :     if ( !json_object_is_type(poAnswerObj, json_type_object) ||
     158                 :             json_object_object_get(poAnswerObj, "db_name") == NULL )
     159                 :     {
     160               0 :         IsError(poAnswerObj, "Database opening failed");
     161                 : 
     162               0 :         json_object_put(poAnswerObj);
     163               0 :         return NULL;
     164                 :     }
     165                 : 
     166              15 :     OGRCouchDBTableLayer* poLayer = new OGRCouchDBTableLayer(this, osTableName);
     167                 : 
     168              30 :     if ( json_object_object_get(poAnswerObj, "update_seq") != NULL )
     169                 :     {
     170              15 :         int nUpdateSeq = json_object_get_int(json_object_object_get(poAnswerObj, "update_seq"));
     171              15 :         poLayer->SetUpdateSeq(nUpdateSeq);
     172                 :     }
     173                 : 
     174              15 :     json_object_put(poAnswerObj);
     175                 : 
     176              15 :     papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
     177              15 :     papoLayers[nLayers ++] = poLayer;
     178                 : 
     179              15 :     return poLayer;
     180                 : }
     181                 : 
     182                 : /************************************************************************/
     183                 : /*                               OpenView()                             */
     184                 : /************************************************************************/
     185                 : 
     186               1 : OGRLayer* OGRCouchDBDataSource::OpenView()
     187                 : {
     188               1 :     OGRCouchDBRowsLayer* poLayer = new OGRCouchDBRowsLayer(this);
     189               1 :     if (!poLayer->BuildFeatureDefn())
     190                 :     {
     191               0 :         delete poLayer;
     192               0 :         return NULL;
     193                 :     }
     194                 : 
     195               1 :     papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
     196               1 :     papoLayers[nLayers ++] = poLayer;
     197                 : 
     198               1 :     return poLayer;
     199                 : }
     200                 : 
     201                 : /************************************************************************/
     202                 : /*                                Open()                                */
     203                 : /************************************************************************/
     204                 : 
     205              96 : int OGRCouchDBDataSource::Open( const char * pszFilename, int bUpdateIn)
     206                 : 
     207                 : {
     208              96 :     int bHTTP = FALSE;
     209              96 :     if (strncmp(pszFilename, "http://", 7) == 0 ||
     210                 :         strncmp(pszFilename, "https://", 8) == 0)
     211               0 :         bHTTP = TRUE;
     212              96 :     else if (!EQUALN(pszFilename, "CouchDB:", 8))
     213              80 :         return FALSE;
     214                 : 
     215              16 :     bReadWrite = bUpdateIn;
     216                 : 
     217              16 :     pszName = CPLStrdup( pszFilename );
     218                 : 
     219              16 :     if (bHTTP)
     220               0 :         osURL = pszFilename;
     221                 :     else
     222              16 :         osURL = pszFilename + 8;
     223              16 :     if (osURL.size() > 0 && osURL[osURL.size() - 1] == '/')
     224               0 :         osURL.resize(osURL.size() - 1);
     225                 : 
     226              16 :     const char* pszUserPwd = CPLGetConfigOption("COUCHDB_USERPWD", NULL);
     227              16 :     if (pszUserPwd)
     228               0 :         osUserPwd = pszUserPwd;
     229                 : 
     230                 : 
     231              16 :     if ((strstr(osURL, "/_design/") && strstr(osURL, "/_view/")) ||
     232                 :         strstr(osURL, "/_all_docs"))
     233                 :     {
     234               1 :         return OpenView() != NULL;
     235                 :     }
     236                 : 
     237                 :     /* If passed with http://useraccount.knownprovider.com/database, do not */
     238                 :     /* try to issue /all_dbs, but directly open the database */
     239              15 :     const char* pszKnowProvider = strstr(osURL, ".iriscouch.com/");
     240              15 :     if (pszKnowProvider != NULL &&
     241                 :         strchr(pszKnowProvider + strlen(".iriscouch.com/"), '/' ) == NULL)
     242                 :     {
     243              15 :         return OpenDatabase() != NULL;
     244                 :     }
     245               0 :     pszKnowProvider = strstr(osURL, ".cloudant.com/");
     246               0 :     if (pszKnowProvider != NULL &&
     247                 :         strchr(pszKnowProvider + strlen(".cloudant.com/"), '/' ) == NULL)
     248                 :     {
     249               0 :         return OpenDatabase() != NULL;
     250                 :     }
     251                 : 
     252                 :     /* Get list of tables */
     253               0 :     json_object* poAnswerObj = GET("/_all_dbs");
     254                 : 
     255               0 :     if (poAnswerObj == NULL)
     256               0 :         return FALSE;
     257                 : 
     258               0 :     if ( !json_object_is_type(poAnswerObj, json_type_array) )
     259                 :     {
     260               0 :         if ( json_object_is_type(poAnswerObj, json_type_object) )
     261                 :         {
     262               0 :             json_object* poError = json_object_object_get(poAnswerObj, "error");
     263               0 :             json_object* poReason = json_object_object_get(poAnswerObj, "reason");
     264                 : 
     265               0 :             const char* pszError = json_object_get_string(poError);
     266               0 :             const char* pszReason = json_object_get_string(poReason);
     267                 : 
     268               0 :             if (pszError && pszReason && strcmp(pszError, "not_found") == 0 &&
     269                 :                 strcmp(pszReason, "missing") == 0)
     270                 :             {
     271               0 :                 json_object_put(poAnswerObj);
     272               0 :                 poAnswerObj = NULL;
     273                 : 
     274               0 :                 CPLErrorReset();
     275                 : 
     276               0 :                 return OpenDatabase() != NULL;
     277                 :             }
     278                 :         }
     279               0 :         if (poAnswerObj)
     280                 :         {
     281               0 :             IsError(poAnswerObj, "Database listing failed");
     282                 : 
     283               0 :             json_object_put(poAnswerObj);
     284               0 :             return FALSE;
     285                 :         }
     286                 :     }
     287                 : 
     288               0 :     int nTables = json_object_array_length(poAnswerObj);
     289               0 :     for(int i=0;i<nTables;i++)
     290                 :     {
     291               0 :         json_object* poAnswerObjDBName = json_object_array_get_idx(poAnswerObj, i);
     292               0 :         if ( json_object_is_type(poAnswerObjDBName, json_type_string) )
     293                 :         {
     294               0 :             const char* pszDBName = json_object_get_string(poAnswerObjDBName);
     295               0 :             if ( strcmp(pszDBName, "_users") != 0 &&
     296                 :                  strcmp(pszDBName, "_replicator") != 0 )
     297                 :             {
     298               0 :                 papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
     299               0 :                 papoLayers[nLayers ++] = new OGRCouchDBTableLayer(this, pszDBName);
     300                 :             }
     301                 :         }
     302                 :     }
     303                 : 
     304               0 :     json_object_put(poAnswerObj);
     305                 : 
     306               0 :     return TRUE;
     307                 : }
     308                 : 
     309                 : 
     310                 : /************************************************************************/
     311                 : /*                           CreateLayer()                              */
     312                 : /************************************************************************/
     313                 : 
     314               0 : OGRLayer   *OGRCouchDBDataSource::CreateLayer( const char *pszName,
     315                 :                                            OGRSpatialReference *poSpatialRef,
     316                 :                                            OGRwkbGeometryType eGType,
     317                 :                                            char ** papszOptions )
     318                 : {
     319               0 :     if (!bReadWrite)
     320                 :     {
     321               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Operation not available in read-only mode");
     322               0 :         return NULL;
     323                 :     }
     324                 : 
     325                 : /* -------------------------------------------------------------------- */
     326                 : /*      Do we already have this layer?  If so, should we blow it        */
     327                 : /*      away?                                                           */
     328                 : /* -------------------------------------------------------------------- */
     329                 :     int iLayer;
     330                 : 
     331               0 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
     332                 :     {
     333               0 :         if( EQUAL(pszName,papoLayers[iLayer]->GetName()) )
     334                 :         {
     335               0 :             if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
     336                 :                 && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
     337                 :             {
     338               0 :                 DeleteLayer( pszName );
     339               0 :                 break;
     340                 :             }
     341                 :             else
     342                 :             {
     343                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     344                 :                           "Layer %s already exists, CreateLayer failed.\n"
     345                 :                           "Use the layer creation option OVERWRITE=YES to "
     346                 :                           "replace it.",
     347               0 :                           pszName );
     348               0 :                 return NULL;
     349                 :             }
     350                 :         }
     351                 :     }
     352                 : 
     353               0 :     char* pszEscapedName = CPLEscapeString(pszName, -1, CPLES_URL);
     354               0 :     CPLString osEscapedName = pszEscapedName;
     355               0 :     CPLFree(pszEscapedName);
     356                 : 
     357                 : /* -------------------------------------------------------------------- */
     358                 : /*      Create "database"                                               */
     359                 : /* -------------------------------------------------------------------- */
     360               0 :     CPLString osURI;
     361               0 :     osURI = "/";
     362               0 :     osURI += osEscapedName;
     363               0 :     json_object* poAnswerObj = PUT(osURI, NULL);
     364                 : 
     365               0 :     if (poAnswerObj == NULL)
     366               0 :         return NULL;
     367                 : 
     368               0 :     if (!IsOK(poAnswerObj, "Layer creation failed"))
     369                 :     {
     370               0 :         json_object_put(poAnswerObj);
     371               0 :         return NULL;
     372                 :     }
     373                 : 
     374               0 :     json_object_put(poAnswerObj);
     375                 : 
     376                 : /* -------------------------------------------------------------------- */
     377                 : /*      Create "spatial index"                                          */
     378                 : /* -------------------------------------------------------------------- */
     379               0 :     int nUpdateSeq = 0;
     380               0 :     if (eGType != wkbNone)
     381                 :     {
     382               0 :         osURI = "/";
     383               0 :         osURI += osEscapedName;
     384               0 :         osURI += "/_design/ogr_spatial";
     385                 : 
     386               0 :         CPLString osContent("{ \"spatial\": { \"spatial\" : \"function(doc) { if (doc.geometry && doc.geometry.coordinates && doc.geometry.coordinates.length != 0) { emit(doc.geometry, null); } } \" } }");
     387                 : 
     388               0 :         poAnswerObj = PUT(osURI, osContent);
     389                 : 
     390               0 :         if (IsOK(poAnswerObj, "Spatial index creation failed"))
     391               0 :             nUpdateSeq ++;
     392                 : 
     393               0 :         json_object_put(poAnswerObj);
     394                 :     }
     395                 : 
     396                 : 
     397                 : /* -------------------------------------------------------------------- */
     398                 : /*      Create validation function                                      */
     399                 : /* -------------------------------------------------------------------- */
     400               0 :     const char* pszUpdatePermissions = CSLFetchNameValueDef(papszOptions, "UPDATE_PERMISSIONS", "LOGGED_USER");
     401               0 :     CPLString osValidation;
     402               0 :     if (EQUAL(pszUpdatePermissions, "LOGGED_USER"))
     403                 :     {
     404               0 :         osValidation = "{\"validate_doc_update\": \"function(new_doc, old_doc, userCtx) { if(!userCtx.name) { throw({forbidden: \\\"Please log in first.\\\"}); } }\" }";
     405                 :     }
     406               0 :     else if (EQUAL(pszUpdatePermissions, "ALL"))
     407                 :     {
     408               0 :         osValidation = "{\"validate_doc_update\": \"function(new_doc, old_doc, userCtx) {  }\" }";
     409                 :     }
     410               0 :     else if (EQUAL(pszUpdatePermissions, "ADMIN"))
     411                 :     {
     412               0 :         osValidation = "{\"validate_doc_update\": \"function(new_doc, old_doc, userCtx) {if (userCtx.roles.indexOf('_admin') === -1) { throw({forbidden: \\\"No changes allowed except by admin.\\\"}); } }\" }";
     413                 :     }
     414               0 :     else if (strncmp(pszUpdatePermissions, "function(", 9) == 0)
     415                 :     {
     416               0 :         osValidation = "{\"validate_doc_update\": \"";
     417               0 :         osValidation += pszUpdatePermissions;
     418               0 :         osValidation += "\"}";
     419                 :     }
     420                 : 
     421               0 :     if (osValidation.size())
     422                 :     {
     423               0 :         osURI = "/";
     424               0 :         osURI += osEscapedName;
     425               0 :         osURI += "/_design/ogr_validation";
     426                 : 
     427               0 :         poAnswerObj = PUT(osURI, osValidation);
     428                 : 
     429               0 :         if (IsOK(poAnswerObj, "Validation function creation failed"))
     430               0 :             nUpdateSeq ++;
     431                 : 
     432               0 :         json_object_put(poAnswerObj);
     433                 :     }
     434                 : 
     435               0 :     int bGeoJSONDocument = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "GEOJSON", "TRUE"));
     436               0 :     int nCoordPrecision = atoi(CSLFetchNameValueDef(papszOptions, "COORDINATE_PRECISION", "-1"));
     437                 : 
     438               0 :     OGRCouchDBTableLayer* poLayer = new OGRCouchDBTableLayer(this, pszName);
     439               0 :     if (nCoordPrecision != -1)
     440               0 :         poLayer->SetCoordinatePrecision(nCoordPrecision);
     441               0 :     poLayer->SetInfoAfterCreation(eGType, poSpatialRef, nUpdateSeq, bGeoJSONDocument);
     442               0 :     papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
     443               0 :     papoLayers[nLayers ++] = poLayer;
     444               0 :     return poLayer;
     445                 : }
     446                 : 
     447                 : /************************************************************************/
     448                 : /*                            DeleteLayer()                             */
     449                 : /************************************************************************/
     450                 : 
     451               0 : void OGRCouchDBDataSource::DeleteLayer( const char *pszLayerName )
     452                 : 
     453                 : {
     454                 :     int iLayer;
     455                 : 
     456                 : /* -------------------------------------------------------------------- */
     457                 : /*      Try to find layer.                                              */
     458                 : /* -------------------------------------------------------------------- */
     459               0 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
     460                 :     {
     461               0 :         if( EQUAL(pszLayerName,papoLayers[iLayer]->GetName()) )
     462               0 :             break;
     463                 :     }
     464                 : 
     465               0 :     if( iLayer == nLayers )
     466                 :     {
     467                 :         CPLError( CE_Failure, CPLE_AppDefined,
     468                 :                   "Attempt to delete layer '%s', but this layer is not known to OGR.",
     469               0 :                   pszLayerName );
     470               0 :         return;
     471                 :     }
     472                 : 
     473               0 :     DeleteLayer(iLayer);
     474                 : }
     475                 : 
     476                 : /************************************************************************/
     477                 : /*                            DeleteLayer()                             */
     478                 : /************************************************************************/
     479                 : 
     480               0 : OGRErr OGRCouchDBDataSource::DeleteLayer(int iLayer)
     481                 : {
     482               0 :     if (!bReadWrite)
     483                 :     {
     484                 :         CPLError(CE_Failure, CPLE_AppDefined,
     485               0 :                  "Operation not available in read-only mode");
     486               0 :         return OGRERR_FAILURE;
     487                 :     }
     488                 : 
     489               0 :     if( iLayer < 0 || iLayer >= nLayers )
     490                 :     {
     491                 :         CPLError( CE_Failure, CPLE_AppDefined,
     492                 :                   "Layer %d not in legal range of 0 to %d.",
     493               0 :                   iLayer, nLayers-1 );
     494               0 :         return OGRERR_FAILURE;
     495                 :     }
     496                 : 
     497               0 :     CPLString osLayerName = GetLayer(iLayer)->GetName();
     498                 : 
     499                 : /* -------------------------------------------------------------------- */
     500                 : /*      Blow away our OGR structures related to the layer.  This is     */
     501                 : /*      pretty dangerous if anything has a reference to this layer!     */
     502                 : /* -------------------------------------------------------------------- */
     503               0 :     CPLDebug( "CouchDB", "DeleteLayer(%s)", osLayerName.c_str() );
     504                 : 
     505               0 :     delete papoLayers[iLayer];
     506                 :     memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
     507               0 :              sizeof(void *) * (nLayers - iLayer - 1) );
     508               0 :     nLayers--;
     509                 : 
     510                 : /* -------------------------------------------------------------------- */
     511                 : /*      Remove from the database.                                       */
     512                 : /* -------------------------------------------------------------------- */
     513                 : 
     514               0 :     char* pszEscapedName = CPLEscapeString(osLayerName, -1, CPLES_URL);
     515               0 :     CPLString osEscapedName = pszEscapedName;
     516               0 :     CPLFree(pszEscapedName);
     517                 : 
     518               0 :     CPLString osURI;
     519               0 :     osURI = "/";
     520               0 :     osURI += osEscapedName;
     521               0 :     json_object* poAnswerObj = DELETE(osURI);
     522                 : 
     523               0 :     if (poAnswerObj == NULL)
     524               0 :         return OGRERR_FAILURE;
     525                 : 
     526               0 :     if (!IsOK(poAnswerObj, "Layer deletion failed"))
     527                 :     {
     528               0 :         json_object_put(poAnswerObj);
     529               0 :         return OGRERR_FAILURE;
     530                 :     }
     531                 : 
     532               0 :     json_object_put(poAnswerObj);
     533                 : 
     534               0 :     return OGRERR_NONE;
     535                 : }
     536                 : 
     537                 : /************************************************************************/
     538                 : /*                             ExecuteSQL()                             */
     539                 : /************************************************************************/
     540                 : 
     541               1 : OGRLayer * OGRCouchDBDataSource::ExecuteSQL( const char *pszSQLCommand,
     542                 :                                           OGRGeometry *poSpatialFilter,
     543                 :                                           const char *pszDialect )
     544                 : 
     545                 : {
     546               1 :     if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
     547                 :         return OGRDataSource::ExecuteSQL( pszSQLCommand,
     548                 :                                           poSpatialFilter,
     549               0 :                                           pszDialect );
     550                 : 
     551                 : /* -------------------------------------------------------------------- */
     552                 : /*      Special case DELLAYER: command.                                 */
     553                 : /* -------------------------------------------------------------------- */
     554               1 :     if( EQUALN(pszSQLCommand,"DELLAYER:",9) )
     555                 :     {
     556               0 :         const char *pszLayerName = pszSQLCommand + 9;
     557                 : 
     558               0 :         while( *pszLayerName == ' ' )
     559               0 :             pszLayerName++;
     560                 : 
     561               0 :         DeleteLayer( pszLayerName );
     562               0 :         return NULL;
     563                 :     }
     564                 : 
     565                 : /* -------------------------------------------------------------------- */
     566                 : /*      Special case 'COMPACT ON ' command.                             */
     567                 : /* -------------------------------------------------------------------- */
     568               1 :     if( EQUALN(pszSQLCommand,"COMPACT ON ",11) )
     569                 :     {
     570               0 :         const char *pszLayerName = pszSQLCommand + 11;
     571                 : 
     572               0 :         while( *pszLayerName == ' ' )
     573               0 :             pszLayerName++;
     574                 : 
     575               0 :         CPLString osURI("/");
     576               0 :         osURI += pszLayerName;
     577               0 :         osURI += "/_compact";
     578                 : 
     579               0 :         json_object* poAnswerObj = POST(osURI, NULL);
     580               0 :         IsError(poAnswerObj, "Database compaction failed");
     581               0 :         json_object_put(poAnswerObj);
     582                 : 
     583               0 :         return NULL;
     584                 :     }
     585                 : 
     586                 : /* -------------------------------------------------------------------- */
     587                 : /*      Special case 'VIEW CLEANUP ON ' command.                        */
     588                 : /* -------------------------------------------------------------------- */
     589               1 :     if( EQUALN(pszSQLCommand,"VIEW CLEANUP ON ",16) )
     590                 :     {
     591               0 :         const char *pszLayerName = pszSQLCommand + 16;
     592                 : 
     593               0 :         while( *pszLayerName == ' ' )
     594               0 :             pszLayerName++;
     595                 : 
     596               0 :         CPLString osURI("/");
     597               0 :         osURI += pszLayerName;
     598               0 :         osURI += "/_view_cleanup";
     599                 : 
     600               0 :         json_object* poAnswerObj = POST(osURI, NULL);
     601               0 :         IsError(poAnswerObj, "View cleanup failed");
     602               0 :         json_object_put(poAnswerObj);
     603                 : 
     604               0 :         return NULL;
     605                 :     }
     606                 : 
     607                 : /* -------------------------------------------------------------------- */
     608                 : /*      Deal with "DELETE FROM layer_name WHERE expression" statement   */
     609                 : /* -------------------------------------------------------------------- */
     610               1 :     if( EQUALN(pszSQLCommand, "DELETE FROM ", 12) )
     611                 :     {
     612               0 :         const char* pszIter = pszSQLCommand + 12;
     613               0 :         while(*pszIter && *pszIter != ' ')
     614               0 :             pszIter ++;
     615               0 :         if (*pszIter == 0)
     616                 :         {
     617               0 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid statement");
     618               0 :             return NULL;
     619                 :         }
     620                 : 
     621               0 :         CPLString osName = pszSQLCommand + 12;
     622               0 :         osName.resize(pszIter - (pszSQLCommand + 12));
     623               0 :         OGRCouchDBLayer* poLayer = (OGRCouchDBLayer*)GetLayerByName(osName);
     624               0 :         if (poLayer == NULL)
     625                 :         {
     626                 :             CPLError(CE_Failure, CPLE_AppDefined,
     627               0 :                      "Unknown layer : %s", osName.c_str());
     628               0 :             return NULL;
     629                 :         }
     630               0 :         if (poLayer->GetLayerType() != COUCHDB_TABLE_LAYER)
     631               0 :             return NULL;
     632               0 :         OGRCouchDBTableLayer* poTableLayer = (OGRCouchDBTableLayer*)poLayer;
     633                 : 
     634               0 :         while(*pszIter && *pszIter == ' ')
     635               0 :             pszIter ++;
     636               0 :         if (!EQUALN(pszIter, "WHERE ", 5))
     637                 :         {
     638               0 :             CPLError(CE_Failure, CPLE_AppDefined, "WHERE clause missing");
     639               0 :             return NULL;
     640                 :         }
     641               0 :         pszIter += 5;
     642                 : 
     643               0 :         const char* pszQuery = pszIter;
     644                 : 
     645                 :         /* Check with the generic SQL engine that this is a valid WHERE clause */
     646               0 :         OGRFeatureQuery oQuery;
     647               0 :         OGRErr eErr = oQuery.Compile( poLayer->GetLayerDefn(), pszQuery );
     648               0 :         if( eErr != OGRERR_NONE )
     649                 :         {
     650               0 :             return NULL;
     651                 :         }
     652                 : 
     653               0 :         swq_expr_node * pNode = (swq_expr_node *) oQuery.GetSWGExpr();
     654               0 :         if (pNode->eNodeType == SNT_OPERATION &&
     655                 :             pNode->nOperation == SWQ_EQ &&
     656                 :             pNode->nSubExprCount == 2 &&
     657               0 :             pNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
     658               0 :             pNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT &&
     659               0 :             pNode->papoSubExpr[0]->field_index == _ID_FIELD &&
     660               0 :             pNode->papoSubExpr[1]->field_type == SWQ_STRING)
     661                 :         {
     662               0 :             poTableLayer->DeleteFeature(pNode->papoSubExpr[1]->string_value);
     663                 :         }
     664                 :         else
     665                 :         {
     666                 :             CPLError(CE_Failure, CPLE_AppDefined,
     667               0 :                      "Invalid WHERE clause. Expecting '_id' = 'a_value'");
     668               0 :             return NULL;
     669                 :         }
     670                 : 
     671                 : 
     672               0 :         return NULL;
     673                 :     }
     674                 : 
     675                 : /* -------------------------------------------------------------------- */
     676                 : /*      Try an optimized implementation when doing only stats           */
     677                 : /* -------------------------------------------------------------------- */
     678               1 :     if (poSpatialFilter == NULL && EQUALN(pszSQLCommand, "SELECT", 6))
     679                 :     {
     680               1 :         OGRLayer* poRet = ExecuteSQLStats(pszSQLCommand);
     681               1 :         if (poRet)
     682               1 :             return poRet;
     683                 :     }
     684                 : 
     685                 :     return OGRDataSource::ExecuteSQL( pszSQLCommand,
     686                 :                                         poSpatialFilter,
     687               0 :                                         pszDialect );
     688                 : }
     689                 : 
     690                 : /************************************************************************/
     691                 : /*                         ExecuteSQLStats()                            */
     692                 : /************************************************************************/
     693                 : 
     694                 : class PointerAutoFree
     695                 : {
     696                 :         void ** m_pp;
     697                 :     public:
     698               4 :         PointerAutoFree(void** pp) { m_pp = pp; }
     699               4 :         ~PointerAutoFree() { CPLFree(*m_pp); *m_pp = NULL; }
     700                 : };
     701                 : 
     702                 : class OGRCouchDBOneLineLayer : public OGRLayer
     703                 : {
     704                 :     public:
     705                 :         OGRFeature* poFeature;
     706                 :         OGRFeatureDefn* poFeatureDefn;
     707                 :         int bEnd;
     708                 : 
     709               1 :         OGRCouchDBOneLineLayer() { poFeature = NULL; poFeatureDefn = NULL; bEnd = FALSE; }
     710               1 :         ~OGRCouchDBOneLineLayer()
     711               1 :         {
     712               1 :             delete poFeature;
     713               1 :             if( poFeatureDefn != NULL )
     714               1 :                 poFeatureDefn->Release();
     715               1 :         }
     716                 : 
     717               0 :         virtual void        ResetReading() { bEnd = FALSE;}
     718               1 :         virtual OGRFeature *GetNextFeature()
     719                 :         {
     720               1 :             if (bEnd) return NULL;
     721               1 :             bEnd = TRUE;
     722               1 :             return poFeature->Clone();
     723                 :         }
     724               0 :         virtual OGRFeatureDefn *GetLayerDefn() { return poFeatureDefn; }
     725               0 :         virtual int         TestCapability( const char * ) { return FALSE; }
     726                 : };
     727                 : 
     728               1 : OGRLayer * OGRCouchDBDataSource::ExecuteSQLStats( const char *pszSQLCommand )
     729                 : {
     730               1 :     swq_select sSelectInfo;
     731               1 :     if( sSelectInfo.preparse( pszSQLCommand ) != CPLE_None )
     732                 :     {
     733               0 :         return NULL;
     734                 :     }
     735                 : 
     736               1 :     if (sSelectInfo.table_count != 1)
     737                 :     {
     738               0 :         return NULL;
     739                 :     }
     740                 : 
     741               1 :     swq_table_def *psTableDef = &sSelectInfo.table_defs[0];
     742               1 :     if( psTableDef->data_source != NULL )
     743                 :     {
     744               0 :         return NULL;
     745                 :     }
     746                 : 
     747                 :     OGRCouchDBLayer* _poSrcLayer =
     748               1 :         (OGRCouchDBLayer* )GetLayerByName( psTableDef->table_name );
     749               1 :     if (_poSrcLayer == NULL)
     750                 :     {
     751               0 :         return NULL;
     752                 :     }
     753               1 :     if (_poSrcLayer->GetLayerType() != COUCHDB_TABLE_LAYER)
     754               0 :         return NULL;
     755                 : 
     756               1 :     OGRCouchDBTableLayer* poSrcLayer = (OGRCouchDBTableLayer* ) _poSrcLayer;
     757                 : 
     758               1 :     int nFieldCount = poSrcLayer->GetLayerDefn()->GetFieldCount();
     759                 : 
     760                 :     swq_field_list sFieldList;
     761               1 :     memset( &sFieldList, 0, sizeof(sFieldList) );
     762               1 :     sFieldList.table_count = sSelectInfo.table_count;
     763               1 :     sFieldList.table_defs = sSelectInfo.table_defs;
     764                 : 
     765               1 :     sFieldList.count = 0;
     766               1 :     sFieldList.names = (char **) CPLMalloc( sizeof(char *) * nFieldCount );
     767                 :     sFieldList.types = (swq_field_type *)
     768               1 :         CPLMalloc( sizeof(swq_field_type) * nFieldCount );
     769                 :     sFieldList.table_ids = (int *)
     770               1 :         CPLMalloc( sizeof(int) * nFieldCount );
     771                 :     sFieldList.ids = (int *)
     772               1 :         CPLMalloc( sizeof(int) * nFieldCount );
     773                 : 
     774               1 :     PointerAutoFree oHolderNames((void**)&(sFieldList.names));
     775               1 :     PointerAutoFree oHolderTypes((void**)&(sFieldList.types));
     776               1 :     PointerAutoFree oHolderTableIds((void**)&(sFieldList.table_ids));
     777               1 :     PointerAutoFree oHolderIds((void**)&(sFieldList.ids));
     778                 : 
     779                 :     int iField;
     780              12 :     for( iField = 0;
     781               6 :          iField < poSrcLayer->GetLayerDefn()->GetFieldCount();
     782                 :          iField++ )
     783                 :     {
     784               5 :         OGRFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
     785               5 :         int iOutField = sFieldList.count++;
     786               5 :         sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef();
     787               5 :         if( poFDefn->GetType() == OFTInteger )
     788               0 :             sFieldList.types[iOutField] = SWQ_INTEGER;
     789               5 :         else if( poFDefn->GetType() == OFTReal )
     790               2 :             sFieldList.types[iOutField] = SWQ_FLOAT;
     791               3 :         else if( poFDefn->GetType() == OFTString )
     792               3 :             sFieldList.types[iOutField] = SWQ_STRING;
     793                 :         else
     794               0 :             sFieldList.types[iOutField] = SWQ_OTHER;
     795                 : 
     796               5 :         sFieldList.table_ids[iOutField] = 0;
     797               5 :         sFieldList.ids[iOutField] = iField;
     798                 :     }
     799                 : 
     800               1 :     CPLString osLastFieldName;
     801               6 :     for( iField = 0; iField < sSelectInfo.result_columns; iField++ )
     802                 :     {
     803               5 :         swq_col_def *psColDef = sSelectInfo.column_defs + iField;
     804               5 :         if (psColDef->field_name == NULL)
     805               0 :             return NULL;
     806                 : 
     807               5 :         if (strcmp(psColDef->field_name, "*") != 0)
     808                 :         {
     809               4 :             if (osLastFieldName.size() == 0)
     810               1 :                 osLastFieldName = psColDef->field_name;
     811               3 :             else if (strcmp(osLastFieldName, psColDef->field_name) != 0)
     812               0 :                 return NULL;
     813                 : 
     814               4 :             if (poSrcLayer->GetLayerDefn()->GetFieldIndex(psColDef->field_name) == -1)
     815               0 :                 return NULL;
     816                 :         }
     817                 : 
     818               5 :         if (!(psColDef->col_func == SWQCF_AVG ||
     819                 :               psColDef->col_func == SWQCF_MIN ||
     820                 :               psColDef->col_func == SWQCF_MAX ||
     821                 :               psColDef->col_func == SWQCF_COUNT ||
     822                 :               psColDef->col_func == SWQCF_SUM))
     823               0 :             return NULL;
     824                 : 
     825               5 :         if (psColDef->distinct_flag) /* TODO: could perhaps be relaxed */
     826               0 :             return NULL;
     827                 :     }
     828                 : 
     829               1 :     if (osLastFieldName.size() == 0)
     830               0 :         return NULL;
     831                 : 
     832                 :     /* Normalize field name */
     833               1 :     int nIndex = poSrcLayer->GetLayerDefn()->GetFieldIndex(osLastFieldName);
     834               1 :     osLastFieldName = poSrcLayer->GetLayerDefn()->GetFieldDefn(nIndex)->GetNameRef();
     835                 : 
     836                 : /* -------------------------------------------------------------------- */
     837                 : /*      Finish the parse operation.                                     */
     838                 : /* -------------------------------------------------------------------- */
     839                 : 
     840               1 :     if( sSelectInfo.parse( &sFieldList, 0 ) != CE_None )
     841                 :     {
     842               0 :         return NULL;
     843                 :     }
     844                 : 
     845               1 :     if (sSelectInfo.join_defs != NULL ||
     846                 :         sSelectInfo.where_expr != NULL ||
     847                 :         sSelectInfo.order_defs != NULL ||
     848                 :         sSelectInfo.query_mode != SWQM_SUMMARY_RECORD)
     849                 :     {
     850               0 :         return NULL;
     851                 :     }
     852                 : 
     853               6 :     for( iField = 0; iField < sSelectInfo.result_columns; iField++ )
     854                 :     {
     855               5 :         swq_col_def *psColDef = sSelectInfo.column_defs + iField;
     856               5 :         if (psColDef->field_index == -1)
     857                 :         {
     858               1 :             if (psColDef->col_func == SWQCF_COUNT)
     859               1 :                 continue;
     860                 : 
     861               0 :             return NULL;
     862                 :         }
     863               4 :         if (psColDef->field_type != SWQ_INTEGER &&
     864                 :             psColDef->field_type != SWQ_FLOAT)
     865                 :         {
     866               0 :             return NULL;
     867                 :         }
     868                 :     }
     869                 : 
     870               1 :     int bFoundFilter = poSrcLayer->HasFilterOnFieldOrCreateIfNecessary(osLastFieldName);
     871               1 :     if (!bFoundFilter)
     872               0 :         return NULL;
     873                 : 
     874               1 :     CPLString osURI = "/";
     875               1 :     osURI += poSrcLayer->GetName();
     876               1 :     osURI += "/_design/ogr_filter_";
     877               1 :     osURI += osLastFieldName;
     878               1 :     osURI += "/_view/filter?reduce=true";
     879                 : 
     880               1 :     json_object* poAnswerObj = GET(osURI);
     881               1 :     json_object* poRows = NULL;
     882               1 :     if (!(poAnswerObj != NULL &&
     883                 :           json_object_is_type(poAnswerObj, json_type_object) &&
     884                 :           (poRows = json_object_object_get(poAnswerObj, "rows")) != NULL &&
     885                 :           json_object_is_type(poRows, json_type_array)))
     886                 :     {
     887               0 :         json_object_put(poAnswerObj);
     888               0 :         return NULL;
     889                 :     }
     890                 : 
     891               1 :     int nLength = json_object_array_length(poRows);
     892               1 :     if (nLength != 1)
     893                 :     {
     894               0 :         json_object_put(poAnswerObj);
     895               0 :         return NULL;
     896                 :     }
     897                 : 
     898               1 :     json_object* poRow = json_object_array_get_idx(poRows, 0);
     899               1 :     if (!(poRow && json_object_is_type(poRow, json_type_object)))
     900                 :     {
     901               0 :         json_object_put(poAnswerObj);
     902               0 :         return NULL;
     903                 :     }
     904                 : 
     905               1 :     json_object* poValue = json_object_object_get(poRow, "value");
     906               1 :     if (!(poValue != NULL && json_object_is_type(poValue, json_type_object)))
     907                 :     {
     908               0 :         json_object_put(poAnswerObj);
     909               0 :         return NULL;
     910                 :     }
     911                 : 
     912               1 :     json_object* poSum = json_object_object_get(poValue, "sum");
     913               1 :     json_object* poCount = json_object_object_get(poValue, "count");
     914               1 :     json_object* poMin = json_object_object_get(poValue, "min");
     915               1 :     json_object* poMax = json_object_object_get(poValue, "max");
     916               1 :     if (poSum != NULL && (json_object_is_type(poSum, json_type_int) ||
     917                 :                             json_object_is_type(poSum, json_type_double)) &&
     918                 :         poCount != NULL && (json_object_is_type(poCount, json_type_int) ||
     919                 :                             json_object_is_type(poCount, json_type_double)) &&
     920                 :         poMin != NULL && (json_object_is_type(poMin, json_type_int) ||
     921                 :                             json_object_is_type(poMin, json_type_double)) &&
     922                 :         poMax != NULL && (json_object_is_type(poMax, json_type_int) ||
     923                 :                             json_object_is_type(poMax, json_type_double)) )
     924                 :     {
     925               1 :         double dfSum = json_object_get_double(poSum);
     926               1 :         int nCount = json_object_get_int(poCount);
     927               1 :         double dfMin = json_object_get_double(poMin);
     928               1 :         double dfMax = json_object_get_double(poMax);
     929               1 :         json_object_put(poAnswerObj);
     930                 : 
     931                 :         //CPLDebug("CouchDB", "sum=%f, count=%d, min=%f, max=%f",
     932                 :         //         dfSum, nCount, dfMin, dfMax);
     933                 : 
     934               1 :         OGRFeatureDefn* poFeatureDefn = new OGRFeatureDefn(poSrcLayer->GetName());
     935               1 :         poFeatureDefn->Reference();
     936                 : 
     937               6 :         for( iField = 0; iField < sSelectInfo.result_columns; iField++ )
     938                 :         {
     939               5 :             swq_col_def *psColDef = sSelectInfo.column_defs + iField;
     940               5 :             OGRFieldDefn oFDefn( "", OFTInteger );
     941                 : 
     942               5 :             if( psColDef->field_alias != NULL )
     943                 :             {
     944               0 :                 oFDefn.SetName(psColDef->field_alias);
     945                 :             }
     946                 :             else
     947                 :             {
     948                 :                 const swq_operation *op = swq_op_registrar::GetOperator(
     949               5 :                     (swq_op) psColDef->col_func );
     950                 :                 oFDefn.SetName( CPLSPrintf( "%s_%s",
     951                 :                                             op->osName.c_str(),
     952               5 :                                             psColDef->field_name ) );
     953                 :             }
     954                 : 
     955               5 :             if( psColDef->col_func == SWQCF_COUNT )
     956               1 :                 oFDefn.SetType( OFTInteger );
     957               4 :             else if (psColDef->field_type == SWQ_INTEGER)
     958               0 :                 oFDefn.SetType( OFTInteger );
     959               4 :             else if (psColDef->field_type == SWQ_FLOAT)
     960               4 :                 oFDefn.SetType( OFTReal );
     961                 : 
     962               5 :             poFeatureDefn->AddFieldDefn(&oFDefn);
     963                 :         }
     964                 : 
     965               1 :         OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
     966                 : 
     967               6 :         for( iField = 0; iField < sSelectInfo.result_columns; iField++ )
     968                 :         {
     969               5 :             swq_col_def *psColDef = sSelectInfo.column_defs + iField;
     970               5 :             switch(psColDef->col_func)
     971                 :             {
     972                 :                 case SWQCF_AVG:
     973               1 :                     if (nCount)
     974               1 :                         poFeature->SetField(iField, dfSum / nCount);
     975               1 :                     break;
     976                 :                 case SWQCF_MIN:
     977               1 :                     poFeature->SetField(iField, dfMin);
     978               1 :                     break;
     979                 :                 case SWQCF_MAX:
     980               1 :                     poFeature->SetField(iField, dfMax);
     981               1 :                     break;
     982                 :                 case SWQCF_COUNT:
     983               1 :                     poFeature->SetField(iField, nCount);
     984               1 :                     break;
     985                 :                 case SWQCF_SUM:
     986               1 :                     poFeature->SetField(iField, dfSum);
     987                 :                     break;
     988                 :                 default:
     989                 :                     break;
     990                 :             }
     991                 :         }
     992                 : 
     993               1 :         poFeature->SetFID(0);
     994                 : 
     995               1 :         OGRCouchDBOneLineLayer* poAnswerLayer = new OGRCouchDBOneLineLayer();
     996               1 :         poAnswerLayer->poFeatureDefn = poFeatureDefn;
     997               1 :         poAnswerLayer->poFeature = poFeature;
     998               1 :         return poAnswerLayer;
     999                 :     }
    1000               0 :     json_object_put(poAnswerObj);
    1001                 : 
    1002               0 :     return NULL;
    1003                 : }
    1004                 : 
    1005                 : /************************************************************************/
    1006                 : /*                          ReleaseResultSet()                          */
    1007                 : /************************************************************************/
    1008                 : 
    1009               1 : void OGRCouchDBDataSource::ReleaseResultSet( OGRLayer * poLayer )
    1010                 : 
    1011                 : {
    1012               1 :     delete poLayer;
    1013               1 : }
    1014                 : 
    1015                 : /************************************************************************/
    1016                 : /*                             REQUEST()                                */
    1017                 : /************************************************************************/
    1018                 : 
    1019              62 : json_object* OGRCouchDBDataSource::REQUEST(const char* pszVerb,
    1020                 :                                            const char* pszURI,
    1021                 :                                            const char* pszData)
    1022                 : {
    1023              62 :     bMustCleanPersistant = TRUE;
    1024                 : 
    1025              62 :     char** papszOptions = NULL;
    1026              62 :     papszOptions = CSLAddString(papszOptions, CPLSPrintf("PERSISTENT=CouchDB:%p", this));
    1027                 : 
    1028              62 :     CPLString osCustomRequest("CUSTOMREQUEST=");
    1029              62 :     osCustomRequest += pszVerb;
    1030              62 :     papszOptions = CSLAddString(papszOptions, osCustomRequest);
    1031                 : 
    1032              62 :     CPLString osPOSTFIELDS("POSTFIELDS=");
    1033              62 :     if (pszData)
    1034               3 :         osPOSTFIELDS += pszData;
    1035              62 :     papszOptions = CSLAddString(papszOptions, osPOSTFIELDS);
    1036                 : 
    1037              62 :     papszOptions = CSLAddString(papszOptions, "HEADERS=Content-Type: application/json");
    1038                 : 
    1039              62 :     if (osUserPwd.size())
    1040                 :     {
    1041               0 :         CPLString osUserPwdOption("USERPWD=");
    1042               0 :         osUserPwdOption += osUserPwd;
    1043               0 :         papszOptions = CSLAddString(papszOptions, osUserPwdOption);
    1044                 :     }
    1045                 : 
    1046              62 :     CPLDebug("CouchDB", "%s %s", pszVerb, pszURI);
    1047              62 :     CPLString osFullURL(osURL);
    1048              62 :     osFullURL += pszURI;
    1049              62 :     CPLPushErrorHandler(CPLQuietErrorHandler);
    1050              62 :     CPLHTTPResult * psResult = CPLHTTPFetch( osFullURL, papszOptions);
    1051              62 :     CPLPopErrorHandler();
    1052              62 :     CSLDestroy(papszOptions);
    1053              62 :     if (psResult == NULL)
    1054               0 :         return NULL;
    1055                 : 
    1056              62 :     const char* pszServer = CSLFetchNameValue(psResult->papszHeaders, "Server");
    1057              62 :     if (pszServer == NULL || !EQUALN(pszServer, "CouchDB", 7))
    1058                 :     {
    1059               0 :         CPLHTTPDestroyResult(psResult);
    1060               0 :         return NULL;
    1061                 :     }
    1062                 : 
    1063              62 :     if (psResult->nDataLen == 0)
    1064                 :     {
    1065               0 :         CPLHTTPDestroyResult(psResult);
    1066               0 :         return NULL;
    1067                 :     }
    1068                 : 
    1069              62 :     json_tokener* jstok = NULL;
    1070              62 :     json_object* jsobj = NULL;
    1071                 : 
    1072              62 :     jstok = json_tokener_new();
    1073              62 :     jsobj = json_tokener_parse_ex(jstok, (const char*)psResult->pabyData, -1);
    1074              62 :     if( jstok->err != json_tokener_success)
    1075                 :     {
    1076                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1077                 :                     "JSON parsing error: %s (at offset %d)",
    1078               0 :                     json_tokener_errors[jstok->err], jstok->char_offset);
    1079                 : 
    1080               0 :         json_tokener_free(jstok);
    1081                 : 
    1082               0 :         CPLHTTPDestroyResult(psResult);
    1083               0 :         return NULL;
    1084                 :     }
    1085              62 :     json_tokener_free(jstok);
    1086                 : 
    1087              62 :     CPLHTTPDestroyResult(psResult);
    1088              62 :     return jsobj;
    1089                 : }
    1090                 : 
    1091                 : /************************************************************************/
    1092                 : /*                               GET()                                  */
    1093                 : /************************************************************************/
    1094                 : 
    1095              59 : json_object* OGRCouchDBDataSource::GET(const char* pszURI)
    1096                 : {
    1097              59 :     return REQUEST("GET", pszURI, NULL);
    1098                 : }
    1099                 : 
    1100                 : /************************************************************************/
    1101                 : /*                               PUT()                                  */
    1102                 : /************************************************************************/
    1103                 : 
    1104               1 : json_object* OGRCouchDBDataSource::PUT(const char* pszURI, const char* pszData)
    1105                 : {
    1106               1 :     return REQUEST("PUT", pszURI, pszData);
    1107                 : }
    1108                 : 
    1109                 : /************************************************************************/
    1110                 : /*                               POST()                                 */
    1111                 : /************************************************************************/
    1112                 : 
    1113               2 : json_object* OGRCouchDBDataSource::POST(const char* pszURI, const char* pszData)
    1114                 : {
    1115               2 :     return REQUEST("POST", pszURI, pszData);
    1116                 : }
    1117                 : 
    1118                 : /************************************************************************/
    1119                 : /*                             DELETE()                                 */
    1120                 : /************************************************************************/
    1121                 : 
    1122               0 : json_object* OGRCouchDBDataSource::DELETE(const char* pszURI)
    1123                 : {
    1124               0 :     return REQUEST("DELETE", pszURI, NULL);
    1125                 : }
    1126                 : 
    1127                 : /************************************************************************/
    1128                 : /*                            IsError()                                 */
    1129                 : /************************************************************************/
    1130                 : 
    1131              31 : int OGRCouchDBDataSource::IsError(json_object* poAnswerObj,
    1132                 :                                   const char* pszErrorMsg)
    1133                 : {
    1134              31 :     if ( poAnswerObj == NULL ||
    1135                 :         !json_object_is_type(poAnswerObj, json_type_object) )
    1136                 :     {
    1137               0 :         return FALSE;
    1138                 :     }
    1139                 : 
    1140              31 :     json_object* poError = json_object_object_get(poAnswerObj, "error");
    1141              31 :     json_object* poReason = json_object_object_get(poAnswerObj, "reason");
    1142                 : 
    1143              31 :     const char* pszError = json_object_get_string(poError);
    1144              31 :     const char* pszReason = json_object_get_string(poReason);
    1145              31 :     if (pszError != NULL)
    1146                 :     {
    1147                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1148                 :                  "%s : %s, %s",
    1149                 :                  pszErrorMsg,
    1150                 :                  pszError ? pszError : "",
    1151               1 :                  pszReason ? pszReason : "");
    1152                 : 
    1153               1 :         return TRUE;
    1154                 :     }
    1155                 : 
    1156              30 :     return FALSE;
    1157                 : }
    1158                 : 
    1159                 : /************************************************************************/
    1160                 : /*                              IsOK()                                  */
    1161                 : /************************************************************************/
    1162                 : 
    1163               1 : int OGRCouchDBDataSource::IsOK(json_object* poAnswerObj,
    1164                 :                                const char* pszErrorMsg)
    1165                 : {
    1166               1 :     if ( poAnswerObj == NULL ||
    1167                 :         !json_object_is_type(poAnswerObj, json_type_object) )
    1168                 :     {
    1169                 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1170               0 :                  pszErrorMsg);
    1171                 : 
    1172               0 :         return FALSE;
    1173                 :     }
    1174                 : 
    1175               1 :     json_object* poOK = json_object_object_get(poAnswerObj, "ok");
    1176               1 :     if ( !poOK )
    1177                 :     {
    1178               1 :         IsError(poAnswerObj, pszErrorMsg);
    1179                 : 
    1180               1 :         return FALSE;
    1181                 :     }
    1182                 : 
    1183               0 :     const char* pszOK = json_object_get_string(poOK);
    1184               0 :     if ( !pszOK || !CSLTestBoolean(pszOK) )
    1185                 :     {
    1186               0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMsg);
    1187                 : 
    1188               0 :         return FALSE;
    1189                 :     }
    1190                 : 
    1191               0 :     return TRUE;
    1192                 : }

Generated by: LCOV version 1.7