LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpgresultlayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 143 135 94.4 %
Date: 2012-12-26 Functions: 13 10 76.9 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpgresultlayer.cpp 24545 2012-06-07 21:28:38Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGRPGResultLayer class, access the resultset from
       6                 :  *           a particular select query done via ExecuteSQL().
       7                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2002, Frank Warmerdam
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "cpl_conv.h"
      32                 : #include "ogr_pg.h"
      33                 : 
      34                 : CPL_CVSID("$Id: ogrpgresultlayer.cpp 24545 2012-06-07 21:28:38Z rouault $");
      35                 : 
      36                 : #define PQexec this_is_an_error
      37                 : 
      38                 : /************************************************************************/
      39                 : /*                          OGRPGResultLayer()                          */
      40                 : /************************************************************************/
      41                 : 
      42              41 : OGRPGResultLayer::OGRPGResultLayer( OGRPGDataSource *poDSIn, 
      43                 :                                     const char * pszRawQueryIn,
      44              41 :                                     PGresult *hInitialResultIn )
      45                 : {
      46              41 :     poDS = poDSIn;
      47                 : 
      48              41 :     iNextShapeId = 0;
      49                 : 
      50              41 :     pszRawStatement = CPLStrdup(pszRawQueryIn);
      51                 : 
      52              41 :     osWHERE = "";
      53                 : 
      54              41 :     BuildFullQueryStatement();
      55                 : 
      56              41 :     poFeatureDefn = ReadResultDefinition(hInitialResultIn);
      57                 : 
      58              41 :     pszGeomTableName = NULL;
      59              41 :     pszGeomTableSchemaName = NULL;
      60                 : 
      61                 :     /* Find at which index the geometry column is */
      62              41 :     int iGeomCol = -1;
      63              41 :     if (pszGeomColumn != NULL)
      64                 :     {
      65                 :         int iRawField;
      66              32 :         for( iRawField = 0; iRawField < PQnfields(hInitialResultIn); iRawField++ )
      67                 :         {
      68              32 :             if( strcmp(PQfname(hInitialResultIn,iRawField), pszGeomColumn) == 0 )
      69                 :             {
      70              16 :                 iGeomCol = iRawField;
      71              16 :                 break;
      72                 :             }
      73                 :         }
      74                 :     }
      75                 : 
      76                 :     /* Determine the table from which the geometry column is extracted */
      77              41 :     if (iGeomCol != -1)
      78                 :     {
      79              16 :         Oid tableOID = PQftable(hInitialResultIn, iGeomCol);
      80              16 :         if (tableOID != InvalidOid)
      81                 :         {
      82              13 :             CPLString osGetTableName;
      83                 :             osGetTableName.Printf("SELECT c.relname, n.nspname FROM pg_class c "
      84              13 :                                   "JOIN pg_namespace n ON c.relnamespace=n.oid WHERE c.oid = %d ", tableOID);
      85              13 :             PGresult* hTableNameResult = OGRPG_PQexec(poDS->GetPGConn(), osGetTableName );
      86              13 :             if( hTableNameResult && PQresultStatus(hTableNameResult) == PGRES_TUPLES_OK)
      87                 :             {
      88              13 :                 if ( PQntuples(hTableNameResult) > 0 )
      89                 :                 {
      90              13 :                     pszGeomTableName = CPLStrdup(PQgetvalue(hTableNameResult,0,0));
      91              13 :                     pszGeomTableSchemaName = CPLStrdup(PQgetvalue(hTableNameResult,0,1));
      92                 :                 }
      93                 :             }
      94              13 :             OGRPGClearResult( hTableNameResult );
      95                 :         }
      96                 :     }
      97                 : 
      98              41 :     if (bHasPostGISGeography)
      99                 :     {
     100                 :         // FIXME? But for the moment, PostGIS 1.5 only handles SRID:4326.
     101               1 :         nSRSId = 4326;
     102                 :     }
     103              41 : }
     104                 : 
     105                 : /************************************************************************/
     106                 : /*                          ~OGRPGResultLayer()                          */
     107                 : /************************************************************************/
     108                 : 
     109              41 : OGRPGResultLayer::~OGRPGResultLayer()
     110                 : 
     111                 : {
     112              41 :     CPLFree( pszRawStatement );
     113              41 :     CPLFree( pszGeomTableName );
     114              41 :     CPLFree( pszGeomTableSchemaName );
     115              41 : }
     116                 : 
     117                 : 
     118                 : /************************************************************************/
     119                 : /*                      BuildFullQueryStatement()                       */
     120                 : /************************************************************************/
     121                 : 
     122              46 : void OGRPGResultLayer::BuildFullQueryStatement()
     123                 : 
     124                 : {
     125              46 :     if( pszQueryStatement != NULL )
     126                 :     {
     127               5 :         CPLFree( pszQueryStatement );
     128               5 :         pszQueryStatement = NULL;
     129                 :     }
     130                 : 
     131              46 :     pszQueryStatement = (char*) CPLMalloc(strlen(pszRawStatement) + strlen(osWHERE) + 40);
     132                 : 
     133              46 :     if (strlen(osWHERE) == 0)
     134              42 :         strcpy(pszQueryStatement, pszRawStatement);
     135                 :     else
     136                 :         sprintf(pszQueryStatement, "SELECT * FROM (%s) AS ogrpgsubquery %s",
     137               4 :                 pszRawStatement, osWHERE.c_str());
     138              46 : }
     139                 : 
     140                 : /************************************************************************/
     141                 : /*                            ResetReading()                            */
     142                 : /************************************************************************/
     143                 : 
     144              68 : void OGRPGResultLayer::ResetReading()
     145                 : 
     146                 : {
     147              68 :     OGRPGLayer::ResetReading();
     148              68 : }
     149                 : 
     150                 : /************************************************************************/
     151                 : /*                          GetFeatureCount()                           */
     152                 : /************************************************************************/
     153                 : 
     154              24 : int OGRPGResultLayer::GetFeatureCount( int bForce )
     155                 : 
     156                 : {
     157              24 :     if( TestCapability(OLCFastFeatureCount) == FALSE )
     158               8 :         return OGRPGLayer::GetFeatureCount( bForce );
     159                 : 
     160              16 :     PGconn              *hPGConn = poDS->GetPGConn();
     161              16 :     PGresult            *hResult = NULL;
     162              16 :     CPLString           osCommand;
     163              16 :     int                 nCount = 0;
     164                 : 
     165                 :     osCommand.Printf(
     166                 :         "SELECT count(*) FROM (%s) AS ogrpgcount",
     167              16 :         pszQueryStatement );
     168                 : 
     169              16 :     hResult = OGRPG_PQexec(hPGConn, osCommand);
     170              16 :     if( hResult != NULL && PQresultStatus(hResult) == PGRES_TUPLES_OK )
     171              16 :         nCount = atoi(PQgetvalue(hResult,0,0));
     172                 :     else
     173               0 :         CPLDebug( "PG", "%s; failed.", osCommand.c_str() );
     174              16 :     OGRPGClearResult( hResult );
     175                 : 
     176              16 :     return nCount;
     177                 : }
     178                 : 
     179                 : 
     180                 : /************************************************************************/
     181                 : /*                           TestCapability()                           */
     182                 : /************************************************************************/
     183                 : 
     184              60 : int OGRPGResultLayer::TestCapability( const char * pszCap )
     185                 : 
     186                 : {
     187              60 :     if( EQUAL(pszCap,OLCFastFeatureCount) ||
     188                 :         EQUAL(pszCap,OLCFastSetNextByIndex) )
     189                 :         return (m_poFilterGeom == NULL || 
     190              36 :                 ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != UNDETERMINED_SRID)) && m_poAttrQuery == NULL;
     191                 : 
     192              24 :     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
     193               0 :         return ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != UNDETERMINED_SRID) && m_poAttrQuery == NULL;
     194                 : 
     195              24 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
     196              10 :         return (bHasPostGISGeometry && nSRSId != UNDETERMINED_SRID) && m_poAttrQuery == NULL;
     197                 :         
     198              14 :     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
     199               2 :         return TRUE;
     200                 : 
     201                 :     else
     202              12 :         return FALSE;
     203                 : }
     204                 : 
     205                 : 
     206                 : /************************************************************************/
     207                 : /*                           GetNextFeature()                           */
     208                 : /************************************************************************/
     209                 : 
     210            2503 : OGRFeature *OGRPGResultLayer::GetNextFeature()
     211                 : 
     212                 : {
     213            2503 :     if( m_poFilterGeom != NULL &&
     214                 :         (bHasPostGISGeometry || bHasPostGISGeography) && nSRSId == UNDETERMINED_SRID )
     215                 :     {
     216               0 :         GetSpatialRef(); /* make sure that we fetch the SRID if not already done */
     217                 :     }
     218                 : 
     219             134 :     for( ; TRUE; )
     220                 :     {
     221                 :         OGRFeature      *poFeature;
     222                 : 
     223            2637 :         poFeature = GetNextRawFeature();
     224            2637 :         if( poFeature == NULL )
     225              39 :             return NULL;
     226                 : 
     227            2598 :         if( (m_poFilterGeom == NULL
     228                 :             || ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != UNDETERMINED_SRID)
     229                 :             || FilterGeometry( poFeature->GetGeometryRef() ) )
     230                 :             && (m_poAttrQuery == NULL
     231                 :                 || m_poAttrQuery->Evaluate( poFeature )) )
     232            2464 :             return poFeature;
     233                 : 
     234             134 :         delete poFeature;
     235                 :     }
     236                 : }
     237                 : 
     238                 : /************************************************************************/
     239                 : /*                          SetSpatialFilter()                          */
     240                 : /************************************************************************/
     241                 : 
     242              16 : void OGRPGResultLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
     243                 : 
     244                 : {
     245              16 :     if( InstallFilter( poGeomIn ) )
     246                 :     {
     247              10 :         if( (bHasPostGISGeometry || bHasPostGISGeography) && nSRSId == UNDETERMINED_SRID )
     248                 :         {
     249               2 :             GetSpatialRef(); /* make sure that we fetch the SRID if not already done */
     250                 :         }
     251                 : 
     252              10 :         if ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != UNDETERMINED_SRID)
     253                 :         {
     254               5 :             if( m_poFilterGeom != NULL)
     255                 :             {
     256                 :                 char szBox3D_1[128];
     257                 :                 char szBox3D_2[128];
     258                 :                 char* pszComma;
     259               4 :                 OGREnvelope  sEnvelope;
     260                 : 
     261               4 :                 m_poFilterGeom->getEnvelope( &sEnvelope );
     262               4 :                 snprintf(szBox3D_1, sizeof(szBox3D_1), "%.12f %.12f", sEnvelope.MinX, sEnvelope.MinY);
     263               8 :                 while((pszComma = strchr(szBox3D_1, ',')) != NULL)
     264               0 :                     *pszComma = '.';
     265               4 :                 snprintf(szBox3D_2, sizeof(szBox3D_2), "%.12f %.12f", sEnvelope.MaxX, sEnvelope.MaxY);
     266               8 :                 while((pszComma = strchr(szBox3D_2, ',')) != NULL)
     267               0 :                     *pszComma = '.';
     268                 :                 osWHERE.Printf("WHERE %s && %s('BOX3D(%s, %s)'::box3d,%d) ",
     269                 :                                OGRPGEscapeColumnName(pszGeomColumn).c_str(),
     270                 :                                (poDS->sPostGISVersion.nMajor >= 2) ? "ST_SetSRID" : "SetSRID",
     271               4 :                                szBox3D_1, szBox3D_2, nSRSId );
     272                 :             }
     273                 :             else
     274                 :             {
     275               1 :                 osWHERE = "";
     276                 :             }
     277                 : 
     278               5 :             BuildFullQueryStatement();
     279                 :         }
     280                 : 
     281              10 :         ResetReading();
     282                 :     }
     283                 : 
     284              16 : }
     285                 : 
     286                 : /************************************************************************/
     287                 : /*                             GetExtent()                              */
     288                 : /*                                                                      */
     289                 : /*      For PostGIS use internal Extend(geometry) function              */
     290                 : /*      in other cases we use standard OGRLayer::GetExtent()            */
     291                 : /************************************************************************/
     292                 : 
     293               5 : OGRErr OGRPGResultLayer::GetExtent( OGREnvelope *psExtent, int bForce )
     294                 : {
     295               5 :     CPLString   osCommand;
     296                 : 
     297                 :     const char* pszExtentFct;
     298               5 :     if (poDS->sPostGISVersion.nMajor >= 2)
     299               0 :         pszExtentFct = "ST_Extent";
     300                 :     else
     301               5 :         pszExtentFct = "Extent";
     302                 : 
     303               5 :     if( (bHasPostGISGeometry || bHasPostGISGeography) && nSRSId == UNDETERMINED_SRID )
     304                 :     {
     305               1 :         GetSpatialRef(); /* make sure that we fetch the SRID if not already done */
     306                 :     }
     307                 : 
     308               5 :     if ( TestCapability(OLCFastGetExtent) )
     309                 :     {
     310                 :         /* Do not take the spatial filter into account */
     311                 :         osCommand.Printf( "SELECT %s(%s) FROM (%s) AS ogrpgextent",
     312                 :                           pszExtentFct, OGRPGEscapeColumnName(pszGeomColumn).c_str(),
     313               2 :                           pszRawStatement );
     314                 :     }
     315               3 :     else if ( bHasPostGISGeography )
     316                 :     {
     317                 :         /* Probably not very efficient, but more efficient than client-side implementation */
     318                 :         osCommand.Printf( "SELECT %s(ST_GeomFromWKB(ST_AsBinary(%s))) FROM (%s) AS ogrpgextent",
     319                 :                           pszExtentFct, OGRPGEscapeColumnName(pszGeomColumn).c_str(),
     320               1 :                           pszRawStatement );
     321                 :     }
     322                 :     
     323               5 :     return RunGetExtentRequest(psExtent, bForce, osCommand);
     324                 : }
     325                 : 
     326                 : /************************************************************************/
     327                 : /*                           GetSpatialRef()                            */
     328                 : /*                                                                      */
     329                 : /*      We override this to try and fetch the table SRID from the       */
     330                 : /*      geometry_columns table if the srsid is UNDETERMINED_SRID        */
     331                 : /*      (meaning we haven't yet even looked for it).                    */
     332                 : /************************************************************************/
     333                 : 
     334               8 : OGRSpatialReference *OGRPGResultLayer::GetSpatialRef()
     335                 : 
     336                 : {
     337               8 :     if( nSRSId == UNDETERMINED_SRID )
     338                 :     {
     339                 :         /* We have to get the SRID of the geometry column, so to be able */
     340                 :         /* to do spatial filtering */
     341               8 :         if (bHasPostGISGeometry)
     342                 :         {
     343               7 :             if (pszGeomTableName != NULL)
     344                 :             {
     345               6 :                 CPLString osName(pszGeomTableSchemaName);
     346               6 :                 osName += ".";
     347               6 :                 osName += pszGeomTableName;
     348               6 :                 OGRPGLayer* poBaseLayer = (OGRPGLayer*) poDS->GetLayerByName(osName);
     349               6 :                 if (poBaseLayer)
     350                 :                 {
     351               6 :                     nSRSId = poBaseLayer->GetSRID();
     352               6 :                 }
     353                 :             }
     354                 : 
     355               7 :             if( nSRSId == UNDETERMINED_SRID )
     356                 :             {
     357               1 :                 CPLString osGetSRID;
     358                 : 
     359                 :                 const char* psGetSRIDFct;
     360               1 :                 if (poDS->sPostGISVersion.nMajor >= 2)
     361               0 :                     psGetSRIDFct = "ST_SRID";
     362                 :                 else
     363               1 :                     psGetSRIDFct = "getsrid";
     364                 : 
     365               1 :                 osGetSRID += "SELECT ";
     366               1 :                 osGetSRID += psGetSRIDFct;
     367               1 :                 osGetSRID += "(";
     368               1 :                 osGetSRID += OGRPGEscapeColumnName(pszGeomColumn);
     369               1 :                 osGetSRID += ") FROM(";
     370               1 :                 osGetSRID += pszRawStatement;
     371               1 :                 osGetSRID += ") AS ogrpggetsrid LIMIT 1";
     372                 : 
     373               1 :                 PGresult* hSRSIdResult = OGRPG_PQexec(poDS->GetPGConn(), osGetSRID );
     374                 : 
     375               1 :                 nSRSId = -1;
     376                 : 
     377               1 :                 if( hSRSIdResult && PQresultStatus(hSRSIdResult) == PGRES_TUPLES_OK)
     378                 :                 {
     379               1 :                     if ( PQntuples(hSRSIdResult) > 0 )
     380               1 :                         nSRSId = atoi(PQgetvalue(hSRSIdResult, 0, 0));
     381                 :                 }
     382                 :                 else
     383                 :                 {
     384                 :                     CPLError( CE_Failure, CPLE_AppDefined,
     385               0 :                                 "%s", PQerrorMessage(poDS->GetPGConn()) );
     386                 :                 }
     387                 : 
     388               1 :                 OGRPGClearResult(hSRSIdResult);
     389                 :             }
     390                 :         }
     391                 :     }
     392                 : 
     393               8 :     return OGRPGLayer::GetSpatialRef();
     394                 : }

Generated by: LCOV version 1.7