LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpgresultlayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 150 136 90.7 %
Date: 2010-01-09 Functions: 11 11 100.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpgresultlayer.cpp 17987 2009-11-10 15:39:16Z 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                 : #include "ogrpgutility.h"
      34                 : 
      35                 : CPL_CVSID("$Id: ogrpgresultlayer.cpp 17987 2009-11-10 15:39:16Z rouault $");
      36                 : 
      37                 : 
      38                 : /************************************************************************/
      39                 : /*                          OGRPGResultLayer()                          */
      40                 : /************************************************************************/
      41                 : 
      42              29 : OGRPGResultLayer::OGRPGResultLayer( OGRPGDataSource *poDSIn, 
      43                 :                                     const char * pszRawQueryIn,
      44              29 :                                     PGresult *hInitialResultIn )
      45                 : {
      46              29 :     poDS = poDSIn;
      47                 : 
      48              29 :     iNextShapeId = 0;
      49                 : 
      50              29 :     pszRawStatement = CPLStrdup(pszRawQueryIn);
      51                 : 
      52              29 :     osWHERE = "";
      53                 : 
      54              29 :     BuildFullQueryStatement();
      55                 : 
      56              29 :     poFeatureDefn = ReadResultDefinition(hInitialResultIn);
      57                 : 
      58                 :     /* We have to get the SRID of the geometry column, so to be able */
      59                 :     /* to do spatial filtering */
      60              29 :     if (bHasPostGISGeometry)
      61                 :     {
      62               7 :         CPLString osGetSRID;
      63               7 :         osGetSRID += "SELECT getsrid(\"";
      64               7 :         osGetSRID += pszGeomColumn;
      65               7 :         osGetSRID += "\") FROM (";
      66               7 :         osGetSRID += pszRawStatement;
      67               7 :         osGetSRID += ") AS ogrpggetsrid LIMIT 1";
      68                 : 
      69               7 :         PGresult* hSRSIdResult = PQexec(poDS->GetPGConn(), osGetSRID );
      70                 : 
      71               7 :         if( hSRSIdResult && PQresultStatus(hSRSIdResult) == PGRES_TUPLES_OK)
      72                 :         {
      73               7 :             if ( PQntuples(hSRSIdResult) > 0 )
      74               7 :                 nSRSId = atoi(PQgetvalue(hSRSIdResult, 0, 0));
      75                 :         }
      76                 :         else
      77                 :         {
      78                 :             CPLError( CE_Failure, CPLE_AppDefined,
      79               0 :                         "%s", PQerrorMessage(poDS->GetPGConn()) );
      80                 :         }
      81                 : 
      82               7 :         OGRPGClearResult(hSRSIdResult);
      83                 :     }
      84              22 :     else if (bHasPostGISGeography)
      85                 :     {
      86                 :         // FIXME? But for the moment, PostGIS 1.5 only handles SRID:4326.
      87               0 :         nSRSId = 4326;
      88                 :     }
      89                 : 
      90                 :     /* Now set the cursor that will fetch the first rows */
      91                 :     /* This is usefull when used in situations like */
      92                 :     /* ds->ReleaseResultSet(ds->ExecuteSQL("SELECT AddGeometryColumn(....)")) */
      93                 :     /* when people don't actually try to get elements */
      94              29 :     SetInitialQueryCursor();
      95              29 : }
      96                 : 
      97                 : /************************************************************************/
      98                 : /*                          ~OGRPGResultLayer()                          */
      99                 : /************************************************************************/
     100                 : 
     101              58 : OGRPGResultLayer::~OGRPGResultLayer()
     102                 : 
     103                 : {
     104              29 :     CPLFree( pszRawStatement );
     105              58 : }
     106                 : 
     107                 : /************************************************************************/
     108                 : /*                        ReadResultDefinition()                        */
     109                 : /*                                                                      */
     110                 : /*      Build a schema from the current resultset.                      */
     111                 : /************************************************************************/
     112                 : 
     113              29 : OGRFeatureDefn *OGRPGResultLayer::ReadResultDefinition(PGresult *hInitialResultIn)
     114                 : 
     115                 : {
     116              29 :     PGresult            *hResult = hInitialResultIn;
     117                 : 
     118                 : /* -------------------------------------------------------------------- */
     119                 : /*      Parse the returned table information.                           */
     120                 : /* -------------------------------------------------------------------- */
     121              29 :     OGRFeatureDefn *poDefn = new OGRFeatureDefn( "sql_statement" );
     122                 :     int            iRawField;
     123                 : 
     124              29 :     poDefn->Reference();
     125                 : 
     126              29 :     for( iRawField = 0; iRawField < PQnfields(hResult); iRawField++ )
     127                 :     {
     128             153 :         OGRFieldDefn    oField( PQfname(hResult,iRawField), OFTString);
     129                 :         Oid             nTypeOID;
     130                 : 
     131             153 :         nTypeOID = PQftype(hResult,iRawField);
     132                 :         
     133             153 :         if( EQUAL(oField.GetNameRef(),"ogc_fid") )
     134                 :         {
     135              10 :             bHasFid = TRUE;
     136              10 :             pszFIDColumn = CPLStrdup(oField.GetNameRef());
     137              10 :             continue;
     138                 :         }
     139             143 :         else if( nTypeOID == poDS->GetGeometryOID()  ||
     140                 :                  nTypeOID == poDS->GetGeographyOID()  ||
     141                 :                  EQUAL(oField.GetNameRef(),"ST_AsText") ||
     142                 :                  EQUAL(oField.GetNameRef(),"ST_AsBinary") ||
     143                 :                  EQUAL(oField.GetNameRef(),"AsBinary") ||
     144                 :                  EQUAL(oField.GetNameRef(),"asEWKT") ||
     145                 :                  EQUAL(oField.GetNameRef(),"asText") )
     146                 :         {
     147               7 :             if (bHasPostGISGeometry || bHasPostGISGeography )
     148                 :             {
     149                 :                 CPLError(CE_Warning, CPLE_AppDefined,
     150               0 :                          "More than one geometry column was found in the result of the SQL request. Only last one will be used");
     151                 :             }
     152               7 :             if (nTypeOID == poDS->GetGeographyOID())
     153               0 :                 bHasPostGISGeography = TRUE;
     154                 :             else
     155               7 :                 bHasPostGISGeometry = TRUE;
     156               7 :             CPLFree(pszGeomColumn);
     157               7 :             pszGeomColumn = CPLStrdup(oField.GetNameRef());
     158               7 :             continue;
     159                 :         }
     160             136 :         else if( EQUAL(oField.GetNameRef(),"WKB_GEOMETRY") )
     161                 :         {
     162               6 :             bHasWkb = TRUE;
     163               6 :             if( nTypeOID == OIDOID )
     164               0 :                 bWkbAsOid = TRUE;
     165               6 :             continue;
     166                 :         }
     167                 : 
     168             130 :         if( nTypeOID == BYTEAOID )
     169                 :         {
     170               4 :             oField.SetType( OFTBinary );
     171                 :         }
     172             156 :         else if( nTypeOID == CHAROID ||
     173                 :                  nTypeOID == TEXTOID ||
     174                 :                  nTypeOID == BPCHAROID ||
     175                 :                  nTypeOID == VARCHAROID )
     176                 :         {
     177              30 :             oField.SetType( OFTString );
     178              30 :             oField.SetWidth( PQfsize(hResult, iRawField) );
     179                 :         }
     180              96 :         else if( nTypeOID == BOOLOID )
     181                 :         {
     182               4 :             oField.SetType( OFTInteger );
     183               4 :             oField.SetWidth( 1 );
     184                 :         }
     185              92 :         else if (nTypeOID == INT2OID )
     186                 :         {
     187               4 :             oField.SetType( OFTInteger );
     188               4 :             oField.SetWidth( 5 );
     189                 :         }
     190              88 :         else if (nTypeOID == INT4OID )
     191                 :         {
     192              16 :             oField.SetType( OFTInteger );
     193                 :         }
     194              72 :         else if ( nTypeOID == INT8OID )
     195                 :         {
     196                 :             /* FIXME: OFTInteger can not handle 64bit integers */
     197               6 :             oField.SetType( OFTInteger );
     198                 :         }
     199              92 :         else if( nTypeOID == FLOAT4OID ||
     200                 :                  nTypeOID == FLOAT8OID ||
     201                 :                  nTypeOID == NUMERICOID )
     202                 :         {
     203              26 :             oField.SetType( OFTReal );
     204                 :         }
     205              40 :         else if ( nTypeOID == INT4ARRAYOID )
     206                 :         {
     207               4 :             oField.SetType ( OFTIntegerList );
     208                 :         }
     209              44 :         else if ( nTypeOID == FLOAT4ARRAYOID ||
     210                 :                   nTypeOID == FLOAT8ARRAYOID )
     211                 :         {
     212               8 :             oField.SetType ( OFTRealList );
     213                 :         }
     214              40 :         else if ( nTypeOID == TEXTARRAYOID ||
     215                 :                   nTypeOID == BPCHARARRAYOID ||
     216                 :                   nTypeOID == VARCHARARRAYOID )
     217                 :         {
     218              12 :             oField.SetType ( OFTStringList );
     219                 :         }
     220              16 :         else if ( nTypeOID == DATEOID )
     221                 :         {
     222               4 :             oField.SetType( OFTDate );
     223                 :         }
     224              12 :         else if ( nTypeOID == TIMEOID )
     225                 :         {
     226               4 :             oField.SetType( OFTTime );
     227                 :         }
     228              16 :         else if ( nTypeOID == TIMESTAMPOID ||
     229                 :                   nTypeOID == TIMESTAMPTZOID )
     230                 :         {
     231                 :             /* We can't deserialize properly timestamp with time zone */
     232                 :             /* with binary cursors */
     233               8 :             if (nTypeOID == TIMESTAMPTZOID)
     234               4 :                 bCanUseBinaryCursor = FALSE;
     235                 : 
     236               8 :             oField.SetType( OFTDateTime );
     237                 :         }
     238                 :         else /* unknown type */
     239                 :         {
     240               0 :             CPLDebug("PG", "Unhandled OID (%d) for column %d. Defaulting to String.", nTypeOID, iRawField);
     241               0 :             oField.SetType( OFTString );
     242                 :         }
     243                 :         
     244             130 :         poDefn->AddFieldDefn( &oField );
     245                 :     }
     246                 : 
     247              29 :     return poDefn;
     248                 : }
     249                 : 
     250                 : /************************************************************************/
     251                 : /*                      BuildFullQueryStatement()                       */
     252                 : /************************************************************************/
     253                 : 
     254              31 : void OGRPGResultLayer::BuildFullQueryStatement()
     255                 : 
     256                 : {
     257              31 :     if( pszQueryStatement != NULL )
     258                 :     {
     259               2 :         CPLFree( pszQueryStatement );
     260               2 :         pszQueryStatement = NULL;
     261                 :     }
     262                 : 
     263              31 :     pszQueryStatement = (char*) CPLMalloc(strlen(pszRawStatement) + strlen(osWHERE) + 40);
     264                 : 
     265              31 :     if (strlen(osWHERE) == 0)
     266              29 :         strcpy(pszQueryStatement, pszRawStatement);
     267                 :     else
     268                 :         sprintf(pszQueryStatement, "SELECT * FROM (%s) AS ogrpgsubquery %s",
     269               2 :                 pszRawStatement, osWHERE.c_str());
     270              31 : }
     271                 : 
     272                 : /************************************************************************/
     273                 : /*                            ResetReading()                            */
     274                 : /************************************************************************/
     275                 : 
     276              14 : void OGRPGResultLayer::ResetReading()
     277                 : 
     278                 : {
     279              14 :     OGRPGLayer::ResetReading();
     280              14 : }
     281                 : 
     282                 : /************************************************************************/
     283                 : /*                          GetFeatureCount()                           */
     284                 : /************************************************************************/
     285                 : 
     286               6 : int OGRPGResultLayer::GetFeatureCount( int bForce )
     287                 : 
     288                 : {
     289               6 :     if( TestCapability(OLCFastFeatureCount) == FALSE )
     290               2 :         return OGRPGLayer::GetFeatureCount( bForce );
     291                 : 
     292               4 :     PGconn              *hPGConn = poDS->GetPGConn();
     293               4 :     PGresult            *hResult = NULL;
     294               4 :     CPLString           osCommand;
     295               4 :     int                 nCount = 0;
     296                 : 
     297                 :     osCommand.Printf(
     298                 :         "SELECT count(*) FROM (%s) AS ogrpgcount",
     299               4 :         pszQueryStatement );
     300                 : 
     301               4 :     hResult = PQexec(hPGConn, osCommand);
     302               4 :     if( hResult != NULL && PQresultStatus(hResult) == PGRES_TUPLES_OK )
     303               4 :         nCount = atoi(PQgetvalue(hResult,0,0));
     304                 :     else
     305               0 :         CPLDebug( "PG", "%s; failed.", osCommand.c_str() );
     306               4 :     OGRPGClearResult( hResult );
     307                 : 
     308               4 :     return nCount;
     309                 : }
     310                 : 
     311                 : 
     312                 : /************************************************************************/
     313                 : /*                           TestCapability()                           */
     314                 : /************************************************************************/
     315                 : 
     316              12 : int OGRPGResultLayer::TestCapability( const char * pszCap )
     317                 : 
     318                 : {
     319              12 :     if( EQUAL(pszCap,OLCFastFeatureCount) ||
     320                 :         EQUAL(pszCap,OLCFastSetNextByIndex) )
     321                 :         return (m_poFilterGeom == NULL || 
     322               8 :                 ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != -2)) && m_poAttrQuery == NULL;
     323                 : 
     324               4 :     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
     325               0 :         return ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != -2) && m_poAttrQuery == NULL;
     326                 : 
     327               4 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
     328               4 :         return (bHasPostGISGeometry && nSRSId != -2) && m_poAttrQuery == NULL;
     329                 :         
     330               0 :     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
     331               0 :         return TRUE;
     332                 : 
     333                 :     else
     334               0 :         return FALSE;
     335                 : }
     336                 : 
     337                 : 
     338                 : /************************************************************************/
     339                 : /*                           GetNextFeature()                           */
     340                 : /************************************************************************/
     341                 : 
     342            2072 : OGRFeature *OGRPGResultLayer::GetNextFeature()
     343                 : 
     344                 : {
     345                 : 
     346               2 :     for( ; TRUE; )
     347                 :     {
     348                 :         OGRFeature      *poFeature;
     349                 : 
     350            2072 :         poFeature = GetNextRawFeature();
     351            2072 :         if( poFeature == NULL )
     352              14 :             return NULL;
     353                 : 
     354            2058 :         if( (m_poFilterGeom == NULL
     355                 :             || ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != -2)
     356                 :             || FilterGeometry( poFeature->GetGeometryRef() ) )
     357                 :             && (m_poAttrQuery == NULL
     358                 :                 || m_poAttrQuery->Evaluate( poFeature )) )
     359            2056 :             return poFeature;
     360                 : 
     361               2 :         delete poFeature;
     362                 :     }
     363                 : }
     364                 : 
     365                 : /************************************************************************/
     366                 : /*                          SetSpatialFilter()                          */
     367                 : /************************************************************************/
     368                 : 
     369               4 : void OGRPGResultLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
     370                 : 
     371                 : {
     372               4 :     if( InstallFilter( poGeomIn ) )
     373                 :     {
     374               4 :         if ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != -2)
     375                 :         {
     376               2 :             if( m_poFilterGeom != NULL)
     377                 :             {
     378               2 :                 OGREnvelope  sEnvelope;
     379                 : 
     380               2 :                 m_poFilterGeom->getEnvelope( &sEnvelope );
     381                 :                 osWHERE.Printf("WHERE \"%s\" && SetSRID('BOX3D(%.12f %.12f, %.12f %.12f)'::box3d,%d) ",
     382                 :                             pszGeomColumn,
     383                 :                             sEnvelope.MinX, sEnvelope.MinY,
     384                 :                             sEnvelope.MaxX, sEnvelope.MaxY,
     385               2 :                             nSRSId );
     386                 :             }
     387                 :             else
     388                 :             {
     389               0 :                 osWHERE = "";
     390                 :             }
     391                 : 
     392               2 :             BuildFullQueryStatement();
     393                 :         }
     394                 : 
     395               4 :         ResetReading();
     396                 :     }
     397                 : 
     398               4 : }
     399                 : 
     400                 : /************************************************************************/
     401                 : /*                             GetExtent()                              */
     402                 : /*                                                                      */
     403                 : /*      For PostGIS use internal Extend(geometry) function              */
     404                 : /*      in other cases we use standard OGRLayer::GetExtent()            */
     405                 : /************************************************************************/
     406                 : 
     407               2 : OGRErr OGRPGResultLayer::GetExtent( OGREnvelope *psExtent, int bForce )
     408                 : {
     409               2 :     CPLString   osCommand;
     410                 : 
     411               2 :     if ( TestCapability(OLCFastGetExtent) )
     412                 :     {
     413                 :         /* Do not take the spatial filter into account */
     414                 :         osCommand.Printf( "SELECT Extent(\"%s\") FROM (%s) AS ogrpgextent", 
     415               1 :                          pszGeomColumn, pszRawStatement );
     416                 :     }
     417               1 :     else if ( bHasPostGISGeography )
     418                 :     {
     419                 :         /* Probably not very efficient, but more efficient than client-side implementation */
     420                 :         osCommand.Printf( "SELECT Extent(ST_GeomFromWKB(ST_AsBinary(\"%s\"))) FROM (%s) AS ogrpgextent", 
     421               0 :                           pszGeomColumn, pszRawStatement );
     422                 :     }
     423                 :     
     424               2 :     return RunGetExtentRequest(psExtent, bForce, osCommand);
     425                 : }

Generated by: LCOV version 1.7