LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpgresultlayer.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 170
Code covered: 89.4 % Executed lines: 152

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpgresultlayer.cpp 19873 2010-06-15 17:51:27Z 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 19873 2010-06-15 17:51:27Z rouault $");
      36                 : 
      37                 : 
      38                 : /************************************************************************/
      39                 : /*                          OGRPGResultLayer()                          */
      40                 : /************************************************************************/
      41                 : 
      42                 : OGRPGResultLayer::OGRPGResultLayer( OGRPGDataSource *poDSIn, 
      43                 :                                     const char * pszRawQueryIn,
      44              32 :                                     PGresult *hInitialResultIn )
      45                 : {
      46              32 :     poDS = poDSIn;
      47                 : 
      48              32 :     iNextShapeId = 0;
      49                 : 
      50              32 :     pszRawStatement = CPLStrdup(pszRawQueryIn);
      51                 : 
      52              32 :     osWHERE = "";
      53                 : 
      54              32 :     BuildFullQueryStatement();
      55                 : 
      56              32 :     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              32 :     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              25 :     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              32 :     SetInitialQueryCursor();
      95              32 : }
      96                 : 
      97                 : /************************************************************************/
      98                 : /*                          ~OGRPGResultLayer()                          */
      99                 : /************************************************************************/
     100                 : 
     101              32 : OGRPGResultLayer::~OGRPGResultLayer()
     102                 : 
     103                 : {
     104              32 :     CPLFree( pszRawStatement );
     105              32 : }
     106                 : 
     107                 : /************************************************************************/
     108                 : /*                        ReadResultDefinition()                        */
     109                 : /*                                                                      */
     110                 : /*      Build a schema from the current resultset.                      */
     111                 : /************************************************************************/
     112                 : 
     113              32 : OGRFeatureDefn *OGRPGResultLayer::ReadResultDefinition(PGresult *hInitialResultIn)
     114                 : 
     115                 : {
     116              32 :     PGresult            *hResult = hInitialResultIn;
     117                 : 
     118                 : /* -------------------------------------------------------------------- */
     119                 : /*      Parse the returned table information.                           */
     120                 : /* -------------------------------------------------------------------- */
     121              32 :     OGRFeatureDefn *poDefn = new OGRFeatureDefn( "sql_statement" );
     122                 :     int            iRawField;
     123                 : 
     124              32 :     poDefn->Reference();
     125                 : 
     126             196 :     for( iRawField = 0; iRawField < PQnfields(hResult); iRawField++ )
     127                 :     {
     128             164 :         OGRFieldDefn    oField( PQfname(hResult,iRawField), OFTString);
     129                 :         Oid             nTypeOID;
     130                 : 
     131             164 :         nTypeOID = PQftype(hResult,iRawField);
     132                 :         
     133             164 :         if( EQUAL(oField.GetNameRef(),"ogc_fid") )
     134                 :         {
     135              10 :             if (bHasFid)
     136                 :             {
     137                 :                 CPLError(CE_Warning, CPLE_AppDefined,
     138               0 :                          "More than one ogc_fid column was found in the result of the SQL request. Only last one will be used");
     139                 :             }
     140              10 :             bHasFid = TRUE;
     141              10 :             CPLFree(pszFIDColumn);
     142              10 :             pszFIDColumn = CPLStrdup(oField.GetNameRef());
     143              23 :             continue;
     144                 :         }
     145             154 :         else if( nTypeOID == poDS->GetGeometryOID()  ||
     146                 :                  nTypeOID == poDS->GetGeographyOID()  ||
     147                 :                  EQUAL(oField.GetNameRef(),"ST_AsText") ||
     148                 :                  EQUAL(oField.GetNameRef(),"ST_AsBinary") ||
     149                 :                  EQUAL(oField.GetNameRef(),"AsBinary") ||
     150                 :                  EQUAL(oField.GetNameRef(),"asEWKT") ||
     151                 :                  EQUAL(oField.GetNameRef(),"asText") )
     152                 :         {
     153               7 :             if (bHasPostGISGeometry || bHasPostGISGeography )
     154                 :             {
     155                 :                 CPLError(CE_Warning, CPLE_AppDefined,
     156               0 :                          "More than one geometry column was found in the result of the SQL request. Only last one will be used");
     157                 :             }
     158               7 :             if (nTypeOID == poDS->GetGeographyOID())
     159               0 :                 bHasPostGISGeography = TRUE;
     160                 :             else
     161               7 :                 bHasPostGISGeometry = TRUE;
     162               7 :             CPLFree(pszGeomColumn);
     163               7 :             pszGeomColumn = CPLStrdup(oField.GetNameRef());
     164                 :             continue;
     165                 :         }
     166             147 :         else if( EQUAL(oField.GetNameRef(),"WKB_GEOMETRY") )
     167                 :         {
     168               6 :             bHasWkb = TRUE;
     169               6 :             if( nTypeOID == OIDOID )
     170               0 :                 bWkbAsOid = TRUE;
     171                 :             continue;
     172                 :         }
     173                 : 
     174             141 :         if( nTypeOID == BYTEAOID )
     175                 :         {
     176               4 :             oField.SetType( OFTBinary );
     177                 :         }
     178             171 :         else if( nTypeOID == CHAROID ||
     179                 :                  nTypeOID == TEXTOID ||
     180                 :                  nTypeOID == BPCHAROID ||
     181                 :                  nTypeOID == VARCHAROID )
     182                 :         {
     183              34 :             oField.SetType( OFTString );
     184                 : 
     185                 :             /* See http://www.mail-archive.com/pgsql-hackers@postgresql.org/msg57726.html */
     186                 :             /* nTypmod = width + 4 */
     187              34 :             int nTypmod = PQfmod(hResult, iRawField);
     188              34 :             if (nTypmod >= 4 && (nTypeOID == BPCHAROID ||
     189                 :                                nTypeOID == VARCHAROID ) )
     190                 :             {
     191              12 :                 oField.SetWidth( nTypmod - 4);
     192                 :             }
     193                 :         }
     194             103 :         else if( nTypeOID == BOOLOID )
     195                 :         {
     196               4 :             oField.SetType( OFTInteger );
     197               4 :             oField.SetWidth( 1 );
     198                 :         }
     199              99 :         else if (nTypeOID == INT2OID )
     200                 :         {
     201               4 :             oField.SetType( OFTInteger );
     202               4 :             oField.SetWidth( 5 );
     203                 :         }
     204              95 :         else if (nTypeOID == INT4OID )
     205                 :         {
     206              16 :             oField.SetType( OFTInteger );
     207                 :         }
     208              79 :         else if ( nTypeOID == INT8OID )
     209                 :         {
     210                 :             /* FIXME: OFTInteger can not handle 64bit integers */
     211               9 :             oField.SetType( OFTInteger );
     212                 :         }
     213              88 :         else if( nTypeOID == FLOAT4OID ||
     214                 :                  nTypeOID == FLOAT8OID )
     215                 :         {
     216              18 :             oField.SetType( OFTReal );
     217                 :         }
     218              52 :         else if( nTypeOID == NUMERICOID )
     219                 :         {
     220                 :             /* See http://www.mail-archive.com/pgsql-hackers@postgresql.org/msg57726.html */
     221                 :             /* typmod = (width << 16) + precision + 4 */
     222               8 :             int nTypmod = PQfmod(hResult, iRawField);
     223               8 :             if (nTypmod >= 4)
     224                 :             {
     225               8 :                 int nWidth = (nTypmod - 4) >> 16;
     226               8 :                 int nPrecision = (nTypmod - 4) & 0xFFFF;
     227              12 :                 if (nWidth <= 10 && nPrecision == 0)
     228                 :                 {
     229               4 :                     oField.SetType( OFTInteger );
     230               4 :                     oField.SetWidth( nWidth );
     231                 :                 }
     232                 :                 else
     233                 :                 {
     234               4 :                     oField.SetType( OFTReal );
     235               4 :                     oField.SetWidth( nWidth );
     236               4 :                     oField.SetPrecision( nPrecision );
     237                 :                 }
     238                 :             }
     239                 :             else
     240               0 :                 oField.SetType( OFTReal );
     241                 :         }
     242              44 :         else if ( nTypeOID == INT4ARRAYOID )
     243                 :         {
     244               4 :             oField.SetType ( OFTIntegerList );
     245                 :         }
     246              52 :         else if ( nTypeOID == FLOAT4ARRAYOID ||
     247                 :                   nTypeOID == FLOAT8ARRAYOID )
     248                 :         {
     249              12 :             oField.SetType ( OFTRealList );
     250                 :         }
     251              40 :         else if ( nTypeOID == TEXTARRAYOID ||
     252                 :                   nTypeOID == BPCHARARRAYOID ||
     253                 :                   nTypeOID == VARCHARARRAYOID )
     254                 :         {
     255              12 :             oField.SetType ( OFTStringList );
     256                 :         }
     257              16 :         else if ( nTypeOID == DATEOID )
     258                 :         {
     259               4 :             oField.SetType( OFTDate );
     260                 :         }
     261              12 :         else if ( nTypeOID == TIMEOID )
     262                 :         {
     263               4 :             oField.SetType( OFTTime );
     264                 :         }
     265              16 :         else if ( nTypeOID == TIMESTAMPOID ||
     266                 :                   nTypeOID == TIMESTAMPTZOID )
     267                 :         {
     268                 :             /* We can't deserialize properly timestamp with time zone */
     269                 :             /* with binary cursors */
     270               8 :             if (nTypeOID == TIMESTAMPTZOID)
     271               4 :                 bCanUseBinaryCursor = FALSE;
     272                 : 
     273               8 :             oField.SetType( OFTDateTime );
     274                 :         }
     275                 :         else /* unknown type */
     276                 :         {
     277               0 :             CPLDebug("PG", "Unhandled OID (%d) for column %d. Defaulting to String.", nTypeOID, iRawField);
     278               0 :             oField.SetType( OFTString );
     279                 :         }
     280                 :         
     281             141 :         poDefn->AddFieldDefn( &oField );
     282                 :     }
     283                 : 
     284              32 :     return poDefn;
     285                 : }
     286                 : 
     287                 : /************************************************************************/
     288                 : /*                      BuildFullQueryStatement()                       */
     289                 : /************************************************************************/
     290                 : 
     291              34 : void OGRPGResultLayer::BuildFullQueryStatement()
     292                 : 
     293                 : {
     294              34 :     if( pszQueryStatement != NULL )
     295                 :     {
     296               2 :         CPLFree( pszQueryStatement );
     297               2 :         pszQueryStatement = NULL;
     298                 :     }
     299                 : 
     300              34 :     pszQueryStatement = (char*) CPLMalloc(strlen(pszRawStatement) + strlen(osWHERE) + 40);
     301                 : 
     302              34 :     if (strlen(osWHERE) == 0)
     303              32 :         strcpy(pszQueryStatement, pszRawStatement);
     304                 :     else
     305                 :         sprintf(pszQueryStatement, "SELECT * FROM (%s) AS ogrpgsubquery %s",
     306               2 :                 pszRawStatement, osWHERE.c_str());
     307              34 : }
     308                 : 
     309                 : /************************************************************************/
     310                 : /*                            ResetReading()                            */
     311                 : /************************************************************************/
     312                 : 
     313              14 : void OGRPGResultLayer::ResetReading()
     314                 : 
     315                 : {
     316              14 :     OGRPGLayer::ResetReading();
     317              14 : }
     318                 : 
     319                 : /************************************************************************/
     320                 : /*                          GetFeatureCount()                           */
     321                 : /************************************************************************/
     322                 : 
     323               6 : int OGRPGResultLayer::GetFeatureCount( int bForce )
     324                 : 
     325                 : {
     326               6 :     if( TestCapability(OLCFastFeatureCount) == FALSE )
     327               2 :         return OGRPGLayer::GetFeatureCount( bForce );
     328                 : 
     329               4 :     PGconn              *hPGConn = poDS->GetPGConn();
     330               4 :     PGresult            *hResult = NULL;
     331               4 :     CPLString           osCommand;
     332               4 :     int                 nCount = 0;
     333                 : 
     334                 :     osCommand.Printf(
     335                 :         "SELECT count(*) FROM (%s) AS ogrpgcount",
     336               4 :         pszQueryStatement );
     337                 : 
     338               4 :     hResult = PQexec(hPGConn, osCommand);
     339               4 :     if( hResult != NULL && PQresultStatus(hResult) == PGRES_TUPLES_OK )
     340               4 :         nCount = atoi(PQgetvalue(hResult,0,0));
     341                 :     else
     342               0 :         CPLDebug( "PG", "%s; failed.", osCommand.c_str() );
     343               4 :     OGRPGClearResult( hResult );
     344                 : 
     345               4 :     return nCount;
     346                 : }
     347                 : 
     348                 : 
     349                 : /************************************************************************/
     350                 : /*                           TestCapability()                           */
     351                 : /************************************************************************/
     352                 : 
     353              12 : int OGRPGResultLayer::TestCapability( const char * pszCap )
     354                 : 
     355                 : {
     356              12 :     if( EQUAL(pszCap,OLCFastFeatureCount) ||
     357                 :         EQUAL(pszCap,OLCFastSetNextByIndex) )
     358                 :         return (m_poFilterGeom == NULL || 
     359               8 :                 ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != -2)) && m_poAttrQuery == NULL;
     360                 : 
     361               4 :     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
     362               0 :         return ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != -2) && m_poAttrQuery == NULL;
     363                 : 
     364               4 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
     365               4 :         return (bHasPostGISGeometry && nSRSId != -2) && m_poAttrQuery == NULL;
     366                 :         
     367               0 :     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
     368               0 :         return TRUE;
     369                 : 
     370                 :     else
     371               0 :         return FALSE;
     372                 : }
     373                 : 
     374                 : 
     375                 : /************************************************************************/
     376                 : /*                           GetNextFeature()                           */
     377                 : /************************************************************************/
     378                 : 
     379            2075 : OGRFeature *OGRPGResultLayer::GetNextFeature()
     380                 : 
     381                 : {
     382                 : 
     383               2 :     for( ; TRUE; )
     384                 :     {
     385                 :         OGRFeature      *poFeature;
     386                 : 
     387            2075 :         poFeature = GetNextRawFeature();
     388            2075 :         if( poFeature == NULL )
     389              14 :             return NULL;
     390                 : 
     391            2061 :         if( (m_poFilterGeom == NULL
     392                 :             || ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != -2)
     393                 :             || FilterGeometry( poFeature->GetGeometryRef() ) )
     394                 :             && (m_poAttrQuery == NULL
     395                 :                 || m_poAttrQuery->Evaluate( poFeature )) )
     396            2059 :             return poFeature;
     397                 : 
     398               2 :         delete poFeature;
     399                 :     }
     400                 : }
     401                 : 
     402                 : /************************************************************************/
     403                 : /*                          SetSpatialFilter()                          */
     404                 : /************************************************************************/
     405                 : 
     406               4 : void OGRPGResultLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
     407                 : 
     408                 : {
     409               4 :     if( InstallFilter( poGeomIn ) )
     410                 :     {
     411               4 :         if ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != -2)
     412                 :         {
     413               2 :             if( m_poFilterGeom != NULL)
     414                 :             {
     415                 :                 char szBox3D_1[128];
     416                 :                 char szBox3D_2[128];
     417                 :                 char* pszComma;
     418               2 :                 OGREnvelope  sEnvelope;
     419                 : 
     420               2 :                 m_poFilterGeom->getEnvelope( &sEnvelope );
     421               2 :                 snprintf(szBox3D_1, sizeof(szBox3D_1), "%.12f %.12f", sEnvelope.MinX, sEnvelope.MinY);
     422               4 :                 while((pszComma = strchr(szBox3D_1, ',')) != NULL)
     423               0 :                     *pszComma = '.';
     424               2 :                 snprintf(szBox3D_2, sizeof(szBox3D_2), "%.12f %.12f", sEnvelope.MaxX, sEnvelope.MaxY);
     425               4 :                 while((pszComma = strchr(szBox3D_2, ',')) != NULL)
     426               0 :                     *pszComma = '.';
     427                 :                 osWHERE.Printf("WHERE \"%s\" && SetSRID('BOX3D(%s, %s)'::box3d,%d) ",
     428               2 :                             pszGeomColumn, szBox3D_1, szBox3D_2, nSRSId );
     429                 :             }
     430                 :             else
     431                 :             {
     432               0 :                 osWHERE = "";
     433                 :             }
     434                 : 
     435               2 :             BuildFullQueryStatement();
     436                 :         }
     437                 : 
     438               4 :         ResetReading();
     439                 :     }
     440                 : 
     441               4 : }
     442                 : 
     443                 : /************************************************************************/
     444                 : /*                             GetExtent()                              */
     445                 : /*                                                                      */
     446                 : /*      For PostGIS use internal Extend(geometry) function              */
     447                 : /*      in other cases we use standard OGRLayer::GetExtent()            */
     448                 : /************************************************************************/
     449                 : 
     450               2 : OGRErr OGRPGResultLayer::GetExtent( OGREnvelope *psExtent, int bForce )
     451                 : {
     452               2 :     CPLString   osCommand;
     453                 : 
     454               2 :     if ( TestCapability(OLCFastGetExtent) )
     455                 :     {
     456                 :         /* Do not take the spatial filter into account */
     457                 :         osCommand.Printf( "SELECT Extent(\"%s\") FROM (%s) AS ogrpgextent", 
     458               1 :                          pszGeomColumn, pszRawStatement );
     459                 :     }
     460               1 :     else if ( bHasPostGISGeography )
     461                 :     {
     462                 :         /* Probably not very efficient, but more efficient than client-side implementation */
     463                 :         osCommand.Printf( "SELECT Extent(ST_GeomFromWKB(ST_AsBinary(\"%s\"))) FROM (%s) AS ogrpgextent", 
     464               0 :                           pszGeomColumn, pszRawStatement );
     465                 :     }
     466                 :     
     467               2 :     return RunGetExtentRequest(psExtent, bForce, osCommand);
     468                 : }

Generated by: LTP GCOV extension version 1.5