LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpgtablelayer.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 938
Code covered: 84.8 % Executed lines: 795

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpgtablelayer.cpp 19974 2010-07-05 18:33:50Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGRPGTableLayer class, access to an existing table.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2000, Frank Warmerdam
      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_pg.h"
      31                 : #include "ogrpgutility.h"
      32                 : #include "cpl_conv.h"
      33                 : #include "cpl_string.h"
      34                 : #include "cpl_error.h"
      35                 : 
      36                 : CPL_CVSID("$Id: ogrpgtablelayer.cpp 19974 2010-07-05 18:33:50Z rouault $");
      37                 : 
      38                 : #define USE_COPY_UNSET  -10
      39                 : static CPLString OGRPGEscapeStringList(PGconn *hPGConn,
      40                 :                                        char** papszItems, int bForInsertOrUpdate);
      41                 : 
      42                 : /************************************************************************/
      43                 : /*                          OGRPGTableLayer()                           */
      44                 : /************************************************************************/
      45                 : 
      46                 : OGRPGTableLayer::OGRPGTableLayer( OGRPGDataSource *poDSIn,
      47                 :                                   CPLString& osCurrentSchema,
      48                 :                                   const char * pszTableNameIn,
      49                 :                                   const char * pszSchemaNameIn,
      50                 :                                   const char * pszGeomColumnIn,
      51                 :                                   int bUpdate,
      52                 :                                   int bAdvertizeGeomColumn,
      53            1537 :                                   int nSRSIdIn )
      54                 : 
      55                 : {
      56            1537 :     poDS = poDSIn;
      57                 : 
      58            1537 :     pszQueryStatement = NULL;
      59                 : 
      60            1537 :     bUpdateAccess = bUpdate;
      61                 : 
      62            1537 :     iNextShapeId = 0;
      63                 : 
      64            1537 :     nSRSId = nSRSIdIn;
      65                 : 
      66            1537 :     bLaunderColumnNames = TRUE;
      67            1537 :     bCopyActive = FALSE;
      68            1537 :     bUseCopy = USE_COPY_UNSET;  // unknown
      69                 : 
      70            1537 :     pszTableName = CPLStrdup( pszTableNameIn );
      71            1537 :     pszSchemaName = NULL; // set in ReadTableDefinition
      72            1537 :     pszSqlTableName = NULL; //set in ReadTableDefinition
      73            1537 :     pszSqlGeomParentTableName = NULL;
      74                 : 
      75                 :     poFeatureDefn = ReadTableDefinition( osCurrentSchema,
      76                 :                                          pszTableName,
      77                 :                                          pszSchemaNameIn,
      78                 :                                          pszGeomColumnIn,
      79            1537 :                                          bAdvertizeGeomColumn );
      80                 : 
      81            1537 :     if( poFeatureDefn )
      82                 :     {
      83            1534 :         ResetReading();
      84                 :         
      85                 :         // check SRID if it's necessary
      86            1534 :         if( nSRSId == -2 )
      87             218 :             GetSpatialRef();
      88                 :     }
      89                 :     
      90            1537 :     bHasWarnedIncompatibleGeom = FALSE;
      91            1537 : }
      92                 : 
      93                 : //************************************************************************/
      94                 : /*                          ~OGRPGTableLayer()                          */
      95                 : /************************************************************************/
      96                 : 
      97            1537 : OGRPGTableLayer::~OGRPGTableLayer()
      98                 : 
      99                 : {
     100            1537 :     EndCopy();
     101            1537 :     CPLFree( pszSqlTableName );
     102            1537 :     CPLFree( pszTableName );
     103            1537 :     CPLFree( pszSqlGeomParentTableName );
     104            1537 :     CPLFree( pszSchemaName );
     105            1537 : }
     106                 : 
     107                 : /************************************************************************/
     108                 : /*                        ReadTableDefinition()                         */
     109                 : /*                                                                      */
     110                 : /*      Build a schema from the named table.  Done by querying the      */
     111                 : /*      catalog.                                                        */
     112                 : /************************************************************************/
     113                 : 
     114                 : OGRFeatureDefn *OGRPGTableLayer::ReadTableDefinition( CPLString& osCurrentSchema,
     115                 :                                                       const char * pszTableIn,
     116                 :                                                       const char * pszSchemaNameIn,
     117                 :                                                       const char * pszGeomColumnIn,
     118            1537 :                                                       int bAdvertizeGeomColumn)
     119                 : 
     120                 : {
     121                 :     PGresult            *hResult;
     122            1537 :     CPLString           osCommand;
     123            1537 :     CPLString           osPrimaryKey;
     124            1537 :     PGconn              *hPGConn = poDS->GetPGConn();
     125                 : 
     126            1537 :     poDS->FlushSoftTransaction();
     127                 : 
     128                 :     /* -------------------------------------------- */
     129                 :     /*          Detect table primary key            */
     130                 :     /* -------------------------------------------- */
     131                 : 
     132                 :     /* -------------------------------------------- */
     133                 :     /*          Check config options                */
     134                 :     /* -------------------------------------------- */
     135            1537 :     osPrimaryKey = CPLGetConfigOption( "PGSQL_OGR_FID", "ogc_fid" );
     136                 : 
     137            1537 :     if (pszSchemaNameIn)
     138            1528 :       pszSchemaName = CPLStrdup( pszSchemaNameIn );
     139               9 :     else if (strlen(osCurrentSchema))
     140               9 :       pszSchemaName = CPLStrdup( osCurrentSchema );
     141                 : 
     142            1537 :     CPLString osSchemaClause;
     143            1537 :     if( pszSchemaName )
     144            1537 :         osSchemaClause.Printf("AND n.nspname='%s'", pszSchemaName);
     145                 : 
     146                 :     const char* pszTypnameEqualsAnyClause;
     147            1537 :     if (poDS->sPostgreSQLVersion.nMajor == 7 && poDS->sPostgreSQLVersion.nMinor <= 3)
     148               0 :         pszTypnameEqualsAnyClause = "ANY(SELECT '{int2, int4, serial}')";
     149                 :     else
     150            1537 :         pszTypnameEqualsAnyClause = "ANY(ARRAY['int2','int4','serial'])";
     151                 : 
     152                 :     /* See #1889 for why we don't use 'AND a.attnum = ANY(i.indkey)' */
     153                 :     osCommand.Printf("SELECT a.attname, a.attnum, t.typname, "
     154                 :               "t.typname = %s AS isfid "
     155                 :               "FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n, pg_index i "
     156                 :               "WHERE a.attnum > 0 AND a.attrelid = c.oid "
     157                 :               "AND a.atttypid = t.oid AND c.relnamespace = n.oid "
     158                 :               "AND c.oid = i.indrelid AND i.indisprimary = 't' "
     159                 :               "AND t.typname !~ '^geom' AND c.relname = '%s' "
     160                 :               "AND (i.indkey[0]=a.attnum OR i.indkey[1]=a.attnum OR i.indkey[2]=a.attnum "
     161                 :               "OR i.indkey[3]=a.attnum OR i.indkey[4]=a.attnum OR i.indkey[5]=a.attnum "
     162                 :               "OR i.indkey[6]=a.attnum OR i.indkey[7]=a.attnum OR i.indkey[8]=a.attnum "
     163                 :               "OR i.indkey[9]=a.attnum) %s ORDER BY a.attnum",
     164            1537 :               pszTypnameEqualsAnyClause, pszTableIn, osSchemaClause.c_str() );
     165                 :      
     166            1537 :     hResult = PQexec(hPGConn, osCommand.c_str() );
     167                 : 
     168            1537 :     if ( hResult && PGRES_TUPLES_OK == PQresultStatus(hResult) )
     169                 :     {
     170            1537 :         if ( PQntuples( hResult ) == 1 && PQgetisnull( hResult,0,0 ) == false )
     171                 :         {
     172                 :             /* Check if single-field PK can be represented as 32-bit integer. */
     173            1295 :             CPLString osValue(PQgetvalue(hResult, 0, 3));
     174            1295 :             if( osValue == "t" )
     175                 :             {
     176            1295 :                 osPrimaryKey.Printf( "%s", PQgetvalue(hResult,0,0) );
     177            1295 :                 CPLDebug( "PG", "Primary key name (FID): %s", osPrimaryKey.c_str() );
     178            1295 :             }
     179                 :         }
     180             242 :         else if ( PQntuples( hResult ) > 1 )
     181                 :         {
     182                 :             CPLError( CE_Warning, CPLE_AppDefined,
     183                 :                       "Multi-column primary key in \'%s\' detected but not supported.",
     184               1 :                       pszTableIn );
     185                 :         }
     186                 : 
     187            1537 :         OGRPGClearResult( hResult );
     188                 :         /* Zero tuples means no PK is defined, perfectly valid case. */
     189                 :     }
     190                 :     else
     191                 :     {
     192                 :         CPLError( CE_Failure, CPLE_AppDefined,
     193               0 :                   "%s", PQerrorMessage(hPGConn) );
     194                 :     }
     195                 : 
     196                 : /* -------------------------------------------------------------------- */
     197                 : /*      Fire off commands to get back the columns of the table.          */
     198                 : /* -------------------------------------------------------------------- */
     199            1537 :     hResult = PQexec(hPGConn, "BEGIN");
     200                 : 
     201            1537 :     if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
     202                 :     {
     203            1537 :         OGRPGClearResult( hResult );
     204                 : 
     205                 :         osCommand.Printf(
     206                 :                  "DECLARE mycursor CURSOR for "
     207                 :                  "SELECT DISTINCT a.attname, t.typname, a.attlen,"
     208                 :                  "       format_type(a.atttypid,a.atttypmod) "
     209                 :                  "FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n "
     210                 :                  "WHERE c.relname = '%s' "
     211                 :                  "AND a.attnum > 0 AND a.attrelid = c.oid "
     212                 :                  "AND a.atttypid = t.oid "
     213                 :                  "AND c.relnamespace=n.oid "
     214                 :                  "%s",
     215            1537 :                  pszTableIn, osSchemaClause.c_str());
     216                 : 
     217            1537 :         hResult = PQexec(hPGConn, osCommand.c_str() );
     218                 :     }
     219                 : 
     220            1537 :     if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
     221                 :     {
     222            1537 :         OGRPGClearResult( hResult );
     223            1537 :         hResult = PQexec(hPGConn, "FETCH ALL in mycursor" );
     224                 :     }
     225                 : 
     226            1537 :     if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
     227                 :     {
     228               0 :         OGRPGClearResult( hResult );
     229                 : 
     230                 :         CPLError( CE_Failure, CPLE_AppDefined,
     231               0 :                   "%s", PQerrorMessage(hPGConn) );
     232               0 :         return NULL;
     233                 :     }
     234                 : 
     235            1537 :     if( PQntuples(hResult) == 0 )
     236                 :     {
     237               3 :         OGRPGClearResult( hResult );
     238                 : 
     239               3 :         hResult = PQexec(hPGConn, "CLOSE mycursor");
     240               3 :         OGRPGClearResult( hResult );
     241                 : 
     242               3 :         hResult = PQexec(hPGConn, "COMMIT");
     243               3 :         OGRPGClearResult( hResult );
     244                 : 
     245                 :         CPLError( CE_Failure, CPLE_AppDefined,
     246                 :                   "No field definitions found for '%s', is it a table?",
     247               3 :                   pszTableIn );
     248               3 :         return NULL;
     249                 :     }
     250                 : 
     251                 : /* -------------------------------------------------------------------- */
     252                 : /*      Parse the returned table information.                           */
     253                 : /* -------------------------------------------------------------------- */
     254            1534 :     CPLString osDefnName;
     255            1534 :     if ( pszSchemaNameIn && osCurrentSchema != pszSchemaNameIn )
     256                 :     {
     257                 :         /* For backwards compatibility, don't report the geometry column name */
     258                 :         /* if it's wkb_geometry */
     259             625 :         if (bAdvertizeGeomColumn && pszGeomColumnIn)
     260               3 :             osDefnName.Printf( "%s.%s(%s)", pszSchemaNameIn, pszTableIn, pszGeomColumnIn );
     261                 :         else
     262             619 :             osDefnName.Printf("%s.%s", pszSchemaNameIn, pszTableIn );
     263             622 :         pszSqlTableName = CPLStrdup(CPLString().Printf("\"%s\".\"%s\"", pszSchemaNameIn, pszTableIn ));
     264                 :     }
     265                 :     else
     266                 :     { 
     267                 :         //no prefix for current_schema in layer name, for backwards compatibility
     268                 :         /* For backwards compatibility, don't report the geometry column name */
     269                 :         /* if it's wkb_geometry */
     270             938 :         if (bAdvertizeGeomColumn && pszGeomColumnIn)
     271              26 :             osDefnName.Printf( "%s(%s)", pszTableIn, pszGeomColumnIn );
     272                 :         else
     273             886 :             osDefnName = pszTableIn;
     274             912 :         pszSqlTableName = CPLStrdup(CPLString().Printf("\"%s\"", pszTableIn ));
     275                 :     }
     276                 : 
     277            1534 :     OGRFeatureDefn *poDefn = new OGRFeatureDefn( osDefnName );
     278                 :     int            iRecord;
     279                 : 
     280            1534 :     poDefn->Reference();
     281            1534 :     poDefn->SetGeomType( wkbNone );
     282            1534 :     if (pszGeomColumnIn)
     283             916 :       pszGeomColumn = CPLStrdup(pszGeomColumnIn);
     284                 : 
     285           16623 :     for( iRecord = 0; iRecord < PQntuples(hResult); iRecord++ )
     286                 :     {
     287           15089 :         const char      *pszType = NULL;
     288           15089 :         const char      *pszFormatType = NULL;
     289           15089 :         OGRFieldDefn    oField( PQgetvalue( hResult, iRecord, 0 ), OFTString);
     290                 : 
     291           15089 :         pszType = PQgetvalue(hResult, iRecord, 1 );
     292           15089 :         pszFormatType = PQgetvalue(hResult,iRecord,3);
     293                 : 
     294                 :         /* TODO: Add detection of other primary key to use as FID */
     295           15089 :         if( EQUAL(oField.GetNameRef(),osPrimaryKey) )
     296                 :         {
     297            1454 :             bHasFid = TRUE;
     298            1454 :             pszFIDColumn = CPLStrdup(oField.GetNameRef());
     299            1454 :             CPLDebug("PG","Using column '%s' as FID for table '%s'", pszFIDColumn, pszTableIn );
     300            3073 :             continue;
     301                 :         }
     302           13635 :         else if( EQUAL(pszType,"geometry") )
     303                 :         {
     304            1416 :             bHasPostGISGeometry = TRUE;
     305            1416 :             if (!pszGeomColumn)
     306             407 :                 pszGeomColumn = CPLStrdup(oField.GetNameRef());
     307            1416 :             poDefn->SetGeomType( wkbUnknown );
     308                 :             continue;
     309                 :         }
     310           12219 :         else if( EQUAL(pszType,"geography") )
     311                 :         {
     312               0 :             bHasPostGISGeography = TRUE;
     313               0 :             if (!pszGeomColumn)
     314               0 :                 pszGeomColumn = CPLStrdup(oField.GetNameRef());
     315                 :             continue;
     316                 :         }
     317           12219 :         else if( EQUAL(oField.GetNameRef(),"WKB_GEOMETRY") )
     318                 :         {
     319             203 :             if (!pszGeomColumn)
     320                 :             {
     321             203 :                 bHasWkb = TRUE;
     322             203 :                 pszGeomColumn = CPLStrdup(oField.GetNameRef());
     323             203 :                 if( EQUAL(pszType,"OID") )
     324               0 :                     bWkbAsOid = TRUE;
     325                 :             }
     326             203 :             poDefn->SetGeomType( wkbUnknown );
     327                 :             continue;
     328                 :         }
     329                 : 
     330           12016 :         if( EQUAL(pszType,"text") )
     331                 :         {
     332              38 :             oField.SetType( OFTString );
     333                 :         }
     334           12284 :         else if( EQUAL(pszType,"_bpchar") ||
     335                 :                  EQUAL(pszType,"_varchar") ||
     336                 :                  EQUAL(pszType,"_text"))
     337                 :         {
     338             306 :             oField.SetType( OFTStringList );
     339                 :         }
     340           18312 :         else if( EQUAL(pszType,"bpchar") || EQUAL(pszType,"varchar") )
     341                 :         {
     342                 :             int nWidth;
     343                 : 
     344            6640 :             nWidth = atoi(PQgetvalue(hResult,iRecord,2));
     345            6640 :             if( nWidth == -1 )
     346                 :             {
     347            6640 :                 if( EQUALN(pszFormatType,"character(",10) )
     348            1883 :                     nWidth = atoi(pszFormatType+10);
     349            4757 :                 else if( EQUALN(pszFormatType,"character varying(",18) )
     350              43 :                     nWidth = atoi(pszFormatType+18);
     351                 :                 else
     352            4714 :                     nWidth = 0;
     353                 :             }
     354            6640 :             oField.SetType( OFTString );
     355            6640 :             oField.SetWidth( nWidth );
     356                 :         }
     357            5032 :         else if( EQUAL(pszType,"bool") )
     358                 :         {
     359              38 :             oField.SetType( OFTInteger );
     360              38 :             oField.SetWidth( 1 );
     361                 :         }
     362            4994 :         else if( EQUAL(pszType,"numeric") )
     363                 :         {
     364             453 :             const char *pszFormatName = PQgetvalue(hResult,iRecord,3);
     365             453 :             const char *pszPrecision = strstr(pszFormatName,",");
     366             453 :             int    nWidth, nPrecision = 0;
     367                 : 
     368             453 :             nWidth = atoi(pszFormatName + 8);
     369             453 :             if( pszPrecision != NULL )
     370             453 :                 nPrecision = atoi(pszPrecision+1);
     371                 : 
     372             453 :             if( nPrecision == 0 )
     373                 :             {
     374                 :                 // FIXME : If nWidth > 10, OFTInteger may not be large enough */
     375             382 :                 oField.SetType( OFTInteger );
     376                 :             }
     377                 :             else
     378              71 :                 oField.SetType( OFTReal );
     379                 : 
     380             453 :             oField.SetWidth( nWidth );
     381             453 :             oField.SetPrecision( nPrecision );
     382                 :         }
     383            4541 :         else if( EQUAL(pszFormatType,"integer[]") )
     384                 :         {
     385              66 :             oField.SetType( OFTIntegerList );
     386                 :         }
     387            4652 :         else if( EQUAL(pszFormatType, "float[]") ||
     388                 :                  EQUAL(pszFormatType, "real[]") ||
     389                 :                  EQUAL(pszFormatType, "double precision[]") )
     390                 :         {
     391             177 :             oField.SetType( OFTRealList );
     392                 :         }
     393            4298 :         else if( EQUAL(pszType,"int2") )
     394                 :         {
     395              38 :             oField.SetType( OFTInteger );
     396              38 :             oField.SetWidth( 5 );
     397                 :         }
     398            4260 :         else if( EQUAL(pszType,"int8") )
     399                 :         {
     400                 :             /* FIXME: OFTInteger can not handle 64bit integers */
     401              38 :             oField.SetType( OFTInteger );
     402                 :         }
     403            4222 :         else if( EQUALN(pszType,"int",3) )
     404                 :         {
     405            1273 :             oField.SetType( OFTInteger );
     406                 :         }
     407            4959 :         else if( EQUALN(pszType,"float",5) ||
     408                 :                  EQUALN(pszType,"double",6) ||
     409                 :                  EQUAL(pszType,"real") )
     410                 :         {
     411            2010 :             oField.SetType( OFTReal );
     412                 :         }
     413             939 :         else if( EQUALN(pszType, "timestamp",9) )
     414                 :         {
     415             415 :             oField.SetType( OFTDateTime );
     416                 :         }
     417             524 :         else if( EQUALN(pszType, "date",4) )
     418                 :         {
     419             310 :             oField.SetType( OFTDate );
     420                 :         }
     421             214 :         else if( EQUALN(pszType, "time",4) )
     422                 :         {
     423             148 :             oField.SetType( OFTTime );
     424                 :         }
     425              66 :         else if( EQUAL(pszType,"bytea") )
     426                 :         {
     427              66 :             oField.SetType( OFTBinary );
     428                 :         }
     429                 : 
     430                 :         else
     431                 :         {
     432                 :             CPLDebug( "PG", "Field %s is of unknown format type %s (type=%s).", 
     433               0 :                       oField.GetNameRef(), pszFormatType, pszType );
     434                 :         }
     435                 : 
     436           12016 :         poDefn->AddFieldDefn( &oField );
     437                 :     }
     438                 : 
     439            1534 :     OGRPGClearResult( hResult );
     440                 : 
     441            1534 :     hResult = PQexec(hPGConn, "CLOSE mycursor");
     442            1534 :     OGRPGClearResult( hResult );
     443                 : 
     444            1534 :     hResult = PQexec(hPGConn, "COMMIT");
     445            1534 :     OGRPGClearResult( hResult );
     446                 : 
     447                 :     // get layer geometry type (for PostGIS dataset)
     448            1534 :     if ( bHasPostGISGeometry || bHasPostGISGeography )
     449                 :     {
     450                 :       /* Get the geometry type and dimensions from the table, or */
     451                 :       /* from its parents if it is a derived table, or from the parent of the parent, etc.. */
     452            1322 :       int bGoOn = TRUE;
     453            4106 :       while(bGoOn)
     454                 :       {
     455                 :         osCommand.Printf(
     456                 :             "SELECT type, coord_dimension%s FROM %s WHERE f_table_name='%s'",
     457                 :             (nSRSId == -2) ? ", srid" : "",
     458                 :             (bHasPostGISGeometry) ? "geometry_columns" : "geography_columns",
     459            1462 :             (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableIn);
     460            1462 :         if (pszGeomColumn)
     461                 :         {
     462                 :             osCommand += CPLString().Printf(" AND %s='%s'",
     463                 :                 (bHasPostGISGeometry) ? "f_geometry_column" : "f_geography_column",
     464            1462 :                 pszGeomColumn);
     465                 :         }
     466            1462 :         if (pszSchemaName)
     467                 :         {
     468            1462 :             osCommand += CPLString().Printf(" AND f_table_schema='%s'", pszSchemaName);
     469                 :         }
     470                 : 
     471            1462 :         hResult = PQexec(hPGConn,osCommand);
     472                 : 
     473            1462 :         if ( hResult && PQntuples(hResult) == 1 && !PQgetisnull(hResult,0,0) )
     474                 :         {
     475            1302 :             char * pszType = PQgetvalue(hResult,0,0);
     476            1302 :             OGRwkbGeometryType nGeomType = wkbUnknown;
     477                 : 
     478            1302 :             nCoordDimension = MAX(2,MIN(3,atoi(PQgetvalue(hResult,0,1))));
     479                 : 
     480            1302 :             if (nSRSId == -2)
     481            1281 :                 nSRSId = atoi(PQgetvalue(hResult,0,2));
     482                 : 
     483                 :             // check only standard OGC geometry types
     484            1302 :             if ( EQUAL(pszType, "POINT") )
     485             364 :                 nGeomType = wkbPoint;
     486             938 :             else if ( EQUAL(pszType,"LINESTRING"))
     487             250 :                 nGeomType = wkbLineString;
     488             688 :             else if ( EQUAL(pszType,"POLYGON"))
     489             220 :                 nGeomType = wkbPolygon;
     490             468 :             else if ( EQUAL(pszType,"MULTIPOINT"))
     491               0 :                 nGeomType = wkbMultiPoint;
     492             468 :             else if ( EQUAL(pszType,"MULTILINESTRING"))
     493             160 :                 nGeomType = wkbMultiLineString;
     494             308 :             else if ( EQUAL(pszType,"MULTIPOLYGON"))
     495               0 :                 nGeomType = wkbMultiPolygon;
     496             308 :             else if ( EQUAL(pszType,"GEOMETRYCOLLECTION"))
     497               0 :                 nGeomType = wkbGeometryCollection;
     498                 : 
     499            1302 :             if( nCoordDimension == 3 && nGeomType != wkbUnknown )
     500              75 :                 nGeomType = (OGRwkbGeometryType) (nGeomType | wkb25DBit);
     501                 : 
     502                 :             CPLDebug("PG","Layer '%s' geometry type: %s:%s, Dim=%d",
     503                 :                      pszTableIn, pszType, OGRGeometryTypeToName(nGeomType),
     504            1302 :                      nCoordDimension );
     505                 : 
     506            1302 :             poDefn->SetGeomType( nGeomType );
     507                 : 
     508            1302 :             bGoOn = FALSE;
     509                 :         }
     510                 :         else
     511                 :         {
     512                 :             /* Fetch the name of the parent table */
     513             160 :             if (pszSchemaName)
     514                 :             {
     515                 :                 osCommand.Printf("SELECT pg_class.relname FROM pg_class WHERE oid = "
     516                 :                                 "(SELECT pg_inherits.inhparent FROM pg_inherits WHERE inhrelid = "
     517                 :                                 "(SELECT c.oid FROM pg_class c, pg_namespace n WHERE c.relname = '%s' AND c.relnamespace=n.oid AND n.nspname = '%s'))",
     518             160 :                                 (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableIn, pszSchemaName );
     519                 :             }
     520                 :             else
     521                 :             {
     522                 :                 osCommand.Printf("SELECT pg_class.relname FROM pg_class WHERE oid = "
     523                 :                                 "(SELECT pg_inherits.inhparent FROM pg_inherits WHERE inhrelid = "
     524                 :                                 "(SELECT pg_class.oid FROM pg_class WHERE relname = '%s'))",
     525               0 :                                 (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableIn );
     526                 :             }
     527                 : 
     528             160 :             OGRPGClearResult( hResult );
     529             160 :             hResult = PQexec(hPGConn, osCommand.c_str() );
     530                 : 
     531             160 :             if ( hResult && PQntuples( hResult ) == 1 && !PQgetisnull( hResult,0,0 ) )
     532                 :             {
     533             140 :                 CPLFree(pszSqlGeomParentTableName);
     534             140 :                 pszSqlGeomParentTableName = CPLStrdup( PQgetvalue(hResult,0,0) );
     535                 :             }
     536                 :             else
     537                 :             {
     538                 :                 /* No more parent : stop recursion */
     539              20 :                 bGoOn = FALSE;
     540                 :             }
     541                 :         }
     542                 : 
     543            1462 :         OGRPGClearResult( hResult );
     544                 :       }
     545                 :     }
     546                 : 
     547            1534 :     return poDefn;
     548                 : }
     549                 : 
     550                 : /************************************************************************/
     551                 : /*                          SetSpatialFilter()                          */
     552                 : /************************************************************************/
     553                 : 
     554               6 : void OGRPGTableLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
     555                 : 
     556                 : {
     557               6 :     if( InstallFilter( poGeomIn ) )
     558                 :     {
     559               6 :         BuildWhere();
     560                 : 
     561               6 :         ResetReading();
     562                 :     }
     563               6 : }
     564                 : 
     565                 : /************************************************************************/
     566                 : /*                             BuildWhere()                             */
     567                 : /*                                                                      */
     568                 : /*      Build the WHERE statement appropriate to the current set of     */
     569                 : /*      criteria (spatial and attribute queries).                       */
     570                 : /************************************************************************/
     571                 : 
     572              62 : void OGRPGTableLayer::BuildWhere()
     573                 : 
     574                 : {
     575              62 :     osWHERE = "";
     576                 : 
     577              70 :     if( m_poFilterGeom != NULL && (bHasPostGISGeometry || bHasPostGISGeography) )
     578                 :     {
     579                 :         char szBox3D_1[128];
     580                 :         char szBox3D_2[128];
     581                 :         char* pszComma;
     582               4 :         OGREnvelope  sEnvelope;
     583                 : 
     584               4 :         m_poFilterGeom->getEnvelope( &sEnvelope );
     585               4 :         snprintf(szBox3D_1, sizeof(szBox3D_1), "%.12f %.12f", sEnvelope.MinX, sEnvelope.MinY);
     586               8 :         while((pszComma = strchr(szBox3D_1, ',')) != NULL)
     587               0 :             *pszComma = '.';
     588               4 :         snprintf(szBox3D_2, sizeof(szBox3D_2), "%.12f %.12f", sEnvelope.MaxX, sEnvelope.MaxY);
     589               8 :         while((pszComma = strchr(szBox3D_2, ',')) != NULL)
     590               0 :             *pszComma = '.';
     591                 :         osWHERE.Printf("WHERE \"%s\" && SetSRID('BOX3D(%s, %s)'::box3d,%d) ",
     592               4 :                        pszGeomColumn, szBox3D_1, szBox3D_2, nSRSId );
     593                 :     }
     594                 : 
     595              62 :     if( strlen(osQuery) > 0 )
     596                 :     {
     597              40 :         if( strlen(osWHERE) == 0 )
     598                 :         {
     599              39 :             osWHERE.Printf( "WHERE %s ", osQuery.c_str()  );
     600                 :         }
     601                 :         else  
     602                 :         {
     603               1 :             osWHERE += "AND ";
     604               1 :             osWHERE += osQuery;
     605                 :         }
     606                 :     }
     607              62 : }
     608                 : 
     609                 : /************************************************************************/
     610                 : /*                      BuildFullQueryStatement()                       */
     611                 : /************************************************************************/
     612                 : 
     613            1629 : void OGRPGTableLayer::BuildFullQueryStatement()
     614                 : 
     615                 : {
     616            1629 :     if( pszQueryStatement != NULL )
     617                 :     {
     618              95 :         CPLFree( pszQueryStatement );
     619              95 :         pszQueryStatement = NULL;
     620                 :     }
     621                 : 
     622            1629 :     CPLString osFields = BuildFields();
     623                 : 
     624                 :     pszQueryStatement = (char *)
     625                 :         CPLMalloc(strlen(osFields)+strlen(osWHERE)
     626            1629 :                   +strlen(pszSqlTableName) + 40);
     627                 :     sprintf( pszQueryStatement,
     628                 :              "SELECT %s FROM %s %s",
     629            1629 :              osFields.c_str(), pszSqlTableName, osWHERE.c_str() );
     630            1629 : }
     631                 : 
     632                 : /************************************************************************/
     633                 : /*                            ResetReading()                            */
     634                 : /************************************************************************/
     635                 : 
     636            1629 : void OGRPGTableLayer::ResetReading()
     637                 : 
     638                 : {
     639            1629 :     bUseCopy = USE_COPY_UNSET;
     640                 : 
     641            1629 :     BuildFullQueryStatement();
     642                 : 
     643            1629 :     OGRPGLayer::ResetReading();
     644            1629 : }
     645                 : 
     646                 : /************************************************************************/
     647                 : /*                           GetNextFeature()                           */
     648                 : /************************************************************************/
     649                 : 
     650             211 : OGRFeature *OGRPGTableLayer::GetNextFeature()
     651                 : 
     652                 : {
     653              32 :     for( ; TRUE; )
     654                 :     {
     655                 :         OGRFeature      *poFeature;
     656                 : 
     657             211 :         poFeature = GetNextRawFeature();
     658             211 :         if( poFeature == NULL )
     659              12 :             return NULL;
     660                 : 
     661                 :         /* We just have to look if there is a geometry filter */
     662                 :         /* If there's a PostGIS geometry column, the spatial filter */
     663                 :         /* is already taken into account in the select request */
     664                 :         /* The attribute filter is always taken into account by the select request */
     665             199 :         if( m_poFilterGeom == NULL
     666                 :             || bHasPostGISGeometry
     667                 :             || bHasPostGISGeography
     668                 :             || FilterGeometry( poFeature->GetGeometryRef() )  )
     669             167 :             return poFeature;
     670                 : 
     671              32 :         delete poFeature;
     672                 :     }
     673                 : }
     674                 : 
     675                 : /************************************************************************/
     676                 : /*                            BuildFields()                             */
     677                 : /*                                                                      */
     678                 : /*      Build list of fields to fetch, performing any required          */
     679                 : /*      transformations (such as on geometry).                          */
     680                 : /************************************************************************/
     681                 : 
     682            1644 : CPLString OGRPGTableLayer::BuildFields()
     683                 : 
     684                 : {
     685            1644 :     int     i = 0;
     686            1644 :     CPLString osFieldList;
     687                 : 
     688            1644 :     if( bHasFid && poFeatureDefn->GetFieldIndex( pszFIDColumn ) == -1 )
     689                 :     {
     690            1564 :         osFieldList += "\"";
     691            1564 :         osFieldList += pszFIDColumn;
     692            1564 :         osFieldList += "\"";
     693                 :     }
     694                 : 
     695            1644 :     if( pszGeomColumn )
     696                 :     {
     697            1636 :         if( strlen(osFieldList) > 0 )
     698            1562 :             osFieldList += ", ";
     699                 : 
     700            1636 :         if( bHasPostGISGeometry )
     701                 :         {
     702            1380 :             if ( poDS->bUseBinaryCursor )
     703                 :             {
     704              82 :                 osFieldList += "AsEWKB(\"";
     705              82 :                 osFieldList += pszGeomColumn;
     706              82 :                 osFieldList += "\")";
     707                 :             }
     708            1298 :             else if ( poDS->sPostGISVersion.nMajor >= 1 )
     709                 :             {
     710             999 :                 osFieldList += "AsEWKT(\"";
     711             999 :                 osFieldList += pszGeomColumn;
     712             999 :                 osFieldList += "\")";
     713                 :             }
     714                 :             else
     715                 :             {
     716             299 :                 osFieldList += "AsText(\"";
     717             299 :                 osFieldList += pszGeomColumn;
     718             299 :                 osFieldList += "\")";
     719                 :             }
     720                 :         }
     721             256 :         else if ( bHasPostGISGeography )
     722                 :         {
     723               0 :             if ( poDS->bUseBinaryCursor )
     724                 :             {
     725               0 :                 osFieldList += "ST_AsBinary(\"";
     726               0 :                 osFieldList += pszGeomColumn;
     727               0 :                 osFieldList += "\")";
     728                 :             }
     729                 :             else
     730                 :             {
     731               0 :                 osFieldList += "ST_AsText(\"";
     732               0 :                 osFieldList += pszGeomColumn;
     733               0 :                 osFieldList += "\")";
     734                 :             }
     735                 :         }
     736                 :         else
     737                 :         {
     738             256 :             osFieldList += "\"";
     739             256 :             osFieldList += pszGeomColumn;
     740             256 :             osFieldList += "\"";
     741                 :         }
     742                 :     }
     743                 : 
     744           14188 :     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
     745                 :     {
     746           12544 :         const char *pszName = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
     747                 : 
     748           12544 :         if( strlen(osFieldList) > 0 )
     749           12538 :             osFieldList += ", ";
     750                 : 
     751                 :         /* With a binary cursor, it is not possible to get the time zone */
     752                 :         /* of a timestamptz column. So we fallback to asking it in text mode */
     753           12544 :         if ( poDS->bUseBinaryCursor &&
     754                 :              poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
     755                 :         {
     756              32 :             osFieldList += "CAST (\"";
     757              32 :             osFieldList += pszName ;
     758              32 :             osFieldList += "\" AS text)";
     759                 :         }
     760                 :         else
     761                 :         {
     762           12512 :             osFieldList += "\"";
     763           12512 :             osFieldList += pszName;
     764           12512 :             osFieldList += "\"" ;
     765                 :         }
     766                 :     }
     767                 : 
     768               0 :     return osFieldList;
     769                 : }
     770                 : 
     771                 : /************************************************************************/
     772                 : /*                         SetAttributeFilter()                         */
     773                 : /************************************************************************/
     774                 : 
     775              56 : OGRErr OGRPGTableLayer::SetAttributeFilter( const char *pszQuery )
     776                 : 
     777                 : {
     778              56 :     if( pszQuery == NULL )
     779              16 :         osQuery = "";
     780                 :     else
     781              40 :         osQuery = pszQuery;
     782                 : 
     783              56 :     BuildWhere();
     784                 : 
     785              56 :     ResetReading();
     786                 : 
     787              56 :     return OGRERR_NONE;
     788                 : }
     789                 : 
     790                 : /************************************************************************/
     791                 : /*                           DeleteFeature()                            */
     792                 : /************************************************************************/
     793                 : 
     794               2 : OGRErr OGRPGTableLayer::DeleteFeature( long nFID )
     795                 : 
     796                 : {
     797               2 :     PGconn      *hPGConn = poDS->GetPGConn();
     798               2 :     PGresult    *hResult = NULL;
     799               2 :     CPLString   osCommand;
     800                 : 
     801                 : /* -------------------------------------------------------------------- */
     802                 : /*      We can only delete features if we have a well defined FID       */
     803                 : /*      column to target.                                               */
     804                 : /* -------------------------------------------------------------------- */
     805               2 :     if( !bHasFid )
     806                 :     {
     807                 :         CPLError( CE_Failure, CPLE_AppDefined,
     808                 :                   "DeleteFeature(%ld) failed.  Unable to delete features in tables without\n"
     809                 :                   "a recognised FID column.",
     810               0 :                   nFID );
     811               0 :         return OGRERR_FAILURE;
     812                 : 
     813                 :     }
     814                 : 
     815                 : /* -------------------------------------------------------------------- */
     816                 : /*      Form the statement to drop the record.                          */
     817                 : /* -------------------------------------------------------------------- */
     818                 :     osCommand.Printf( "DELETE FROM %s WHERE \"%s\" = %ld",
     819               2 :                       pszSqlTableName, pszFIDColumn, nFID );
     820                 : 
     821                 : /* -------------------------------------------------------------------- */
     822                 : /*      Execute the delete.                                             */
     823                 : /* -------------------------------------------------------------------- */
     824                 :     OGRErr eErr;
     825                 : 
     826               2 :     eErr = poDS->SoftStartTransaction();
     827               2 :     if( eErr != OGRERR_NONE )
     828               0 :         return eErr;
     829                 : 
     830               2 :     hResult = PQexec(hPGConn, osCommand);
     831                 : 
     832               2 :     if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
     833                 :     {
     834                 :         CPLError( CE_Failure, CPLE_AppDefined,
     835                 :                   "DeleteFeature() DELETE statement failed.\n%s",
     836               0 :                   PQerrorMessage(hPGConn) );
     837                 : 
     838               0 :         OGRPGClearResult( hResult );
     839                 : 
     840               0 :         poDS->SoftRollback();
     841               0 :         eErr = OGRERR_FAILURE;
     842                 :     }
     843                 :     else
     844                 :     {
     845               2 :         OGRPGClearResult( hResult );
     846                 : 
     847               2 :         eErr = poDS->SoftCommit();
     848                 :     }
     849                 : 
     850               2 :     return eErr;
     851                 : }
     852                 : 
     853                 : /************************************************************************/
     854                 : /*                          AppendFieldValue()                          */
     855                 : /*                                                                      */
     856                 : /* Used by CreateFeatureViaInsert() and SetFeature() to format a        */
     857                 : /* non-empty field value                                                */
     858                 : /************************************************************************/
     859                 : 
     860                 : void OGRPGTableLayer::AppendFieldValue(PGconn *hPGConn, CPLString& osCommand,
     861            4294 :                                        OGRFeature* poFeature, int i)
     862                 : {
     863            4294 :     int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
     864                 : 
     865                 :     // We need special formatting for integer list values.
     866            4294 :     if(  nOGRFieldType == OFTIntegerList )
     867                 :     {
     868               2 :         int nCount, nOff = 0, j;
     869               2 :         const int *panItems = poFeature->GetFieldAsIntegerList(i,&nCount);
     870               2 :         char *pszNeedToFree = NULL;
     871                 : 
     872               2 :         pszNeedToFree = (char *) CPLMalloc(nCount * 13 + 10);
     873               2 :         strcpy( pszNeedToFree, "'{" );
     874               6 :         for( j = 0; j < nCount; j++ )
     875                 :         {
     876               4 :             if( j != 0 )
     877               2 :                 strcat( pszNeedToFree+nOff, "," );
     878                 : 
     879               4 :             nOff += strlen(pszNeedToFree+nOff);
     880               4 :             sprintf( pszNeedToFree+nOff, "%d", panItems[j] );
     881                 :         }
     882               2 :         strcat( pszNeedToFree+nOff, "}'" );
     883                 : 
     884               2 :         osCommand += pszNeedToFree;
     885               2 :         CPLFree(pszNeedToFree);
     886                 : 
     887               2 :         return;
     888                 :     }
     889                 : 
     890                 :     // We need special formatting for real list values.
     891            4292 :     else if( nOGRFieldType == OFTRealList )
     892                 :     {
     893              16 :         int nCount, nOff = 0, j;
     894              16 :         const double *padfItems =poFeature->GetFieldAsDoubleList(i,&nCount);
     895              16 :         char *pszNeedToFree = NULL;
     896                 : 
     897              16 :         pszNeedToFree = (char *) CPLMalloc(nCount * 40 + 10);
     898              16 :         strcpy( pszNeedToFree, "'{" );
     899              48 :         for( j = 0; j < nCount; j++ )
     900                 :         {
     901              32 :             if( j != 0 )
     902              16 :                 strcat( pszNeedToFree+nOff, "," );
     903                 : 
     904              32 :             nOff += strlen(pszNeedToFree+nOff);
     905              32 :             sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
     906                 :             //Check for special values. They need to be quoted.
     907              32 :             if( strcmp( pszNeedToFree+nOff, "nan" ) == 0 )
     908               8 :                 sprintf( pszNeedToFree+nOff, "NaN" );
     909              24 :             else if( strcmp( pszNeedToFree+nOff, "inf" ) == 0 )
     910               8 :                 sprintf( pszNeedToFree+nOff, "Infinity" );
     911              16 :             else if( strcmp( pszNeedToFree+nOff, "-inf" ) == 0 )
     912               8 :                 sprintf( pszNeedToFree+nOff, "-Infinity" );
     913                 : 
     914              32 :             char* pszComma = strchr(pszNeedToFree+nOff, ',');
     915              32 :             if (pszComma)
     916               0 :                 *pszComma = '.';
     917                 :         }
     918              16 :         strcat( pszNeedToFree+nOff, "}'" );
     919                 : 
     920              16 :         osCommand += pszNeedToFree;
     921              16 :         CPLFree(pszNeedToFree);
     922                 : 
     923              16 :         return;
     924                 :     }
     925                 : 
     926                 :     // We need special formatting for string list values.
     927            4276 :     else if( nOGRFieldType == OFTStringList )
     928                 :     {
     929               6 :         char **papszItems = poFeature->GetFieldAsStringList(i);
     930                 : 
     931               6 :         osCommand += OGRPGEscapeStringList(hPGConn, papszItems, TRUE);
     932                 : 
     933               6 :         return;
     934                 :     }
     935                 : 
     936                 :     // Binary formatting
     937            4270 :     else if( nOGRFieldType == OFTBinary )
     938                 :     {
     939               2 :         osCommand += "'";
     940                 : 
     941               2 :         int nLen = 0;
     942               2 :         GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
     943               2 :         char* pszBytea = GByteArrayToBYTEA( pabyData, nLen);
     944                 : 
     945               2 :         osCommand += pszBytea;
     946                 : 
     947               2 :         CPLFree(pszBytea);
     948               2 :         osCommand += "'";
     949                 : 
     950               2 :         return;
     951                 :     }
     952                 : 
     953                 :     // Flag indicating NULL or not-a-date date value
     954                 :     // e.g. 0000-00-00 - there is no year 0
     955            4268 :     OGRBoolean bIsDateNull = FALSE;
     956                 : 
     957            4268 :     const char *pszStrValue = poFeature->GetFieldAsString(i);
     958                 : 
     959                 :     // Check if date is NULL: 0000-00-00
     960            4268 :     if( nOGRFieldType == OFTDate )
     961                 :     {
     962               2 :         if( EQUALN( pszStrValue, "0000", 4 ) )
     963                 :         {
     964               0 :             pszStrValue = "NULL";
     965               0 :             bIsDateNull = TRUE;
     966                 :         }
     967                 :     }
     968            4266 :     else if ( nOGRFieldType == OFTReal )
     969                 :     {
     970             106 :         char* pszComma = strchr((char*)pszStrValue, ',');
     971             106 :         if (pszComma)
     972               0 :             *pszComma = '.';
     973                 :         //Check for special values. They need to be quoted.
     974             106 :         if( strcmp( pszStrValue, "nan" ) == 0 )
     975               4 :             pszStrValue = "'NaN'";
     976             102 :         else if( strcmp( pszStrValue, "inf" ) == 0 )
     977               4 :             pszStrValue = "'Infinity'";
     978              98 :         else if( strcmp( pszStrValue, "-inf" ) == 0 )
     979               4 :             pszStrValue = "'-Infinity'";
     980                 :     }
     981                 : 
     982            4394 :     if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTReal
     983                 :         && !bIsDateNull )
     984                 :     {
     985                 :         osCommand += OGRPGEscapeString(hPGConn, pszStrValue,
     986                 :                                         poFeatureDefn->GetFieldDefn(i)->GetWidth(),
     987             126 :                                         poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
     988                 :     }
     989                 :     else
     990                 :     {
     991            4142 :         osCommand += pszStrValue;
     992                 :     }
     993                 : }
     994                 : 
     995                 : /************************************************************************/
     996                 : /*                             SetFeature()                             */
     997                 : /*                                                                      */
     998                 : /*      SetFeature() is implemented by an UPDATE SQL command            */
     999                 : /************************************************************************/
    1000                 : 
    1001            2004 : OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
    1002                 : 
    1003                 : {
    1004            2004 :     PGconn              *hPGConn = poDS->GetPGConn();
    1005            2004 :     PGresult            *hResult = NULL;
    1006            2004 :     CPLString           osCommand;
    1007            2004 :     int                 i = 0;
    1008            2004 :     int                 bNeedComma = FALSE;
    1009            2004 :     OGRErr              eErr = OGRERR_FAILURE;
    1010                 : 
    1011            2004 :     if( NULL == poFeature )
    1012                 :     {
    1013                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1014               0 :                   "NULL pointer to OGRFeature passed to SetFeature()." );
    1015               0 :         return eErr;
    1016                 :     }
    1017                 : 
    1018            2004 :     if( poFeature->GetFID() == OGRNullFID )
    1019                 :     {
    1020                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1021               0 :                   "FID required on features given to SetFeature()." );
    1022               0 :         return eErr;
    1023                 :     }
    1024                 : 
    1025            2004 :     if( !bHasFid )
    1026                 :     {
    1027                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1028                 :                   "Unable to update features in tables without\n"
    1029               0 :                   "a recognised FID column.");
    1030               0 :         return eErr;
    1031                 : 
    1032                 :     }
    1033                 : 
    1034            2004 :     eErr = poDS->SoftStartTransaction();
    1035            2004 :     if( eErr != OGRERR_NONE )
    1036                 :     {
    1037               0 :         return eErr;
    1038                 :     }
    1039                 : 
    1040                 : /* -------------------------------------------------------------------- */
    1041                 : /*      Form the UPDATE command.                                        */
    1042                 : /* -------------------------------------------------------------------- */
    1043            2004 :     osCommand.Printf( "UPDATE %s SET ", pszSqlTableName );
    1044                 : 
    1045                 :     /* Set the geometry */
    1046            2004 :     if( bHasWkb )
    1047                 :     {
    1048            1002 :         osCommand += "WKB_GEOMETRY = ";
    1049            1002 :         if ( poFeature->GetGeometryRef() != NULL )
    1050                 :         {
    1051               1 :             if( !bWkbAsOid  )
    1052                 :             {
    1053               1 :                 char    *pszBytea = GeometryToBYTEA( poFeature->GetGeometryRef() );
    1054                 : 
    1055               1 :                 if( pszBytea != NULL )
    1056                 :                 {
    1057               1 :                     osCommand = osCommand + "'" + pszBytea + "'";
    1058               1 :                     CPLFree( pszBytea );
    1059                 :                 }
    1060                 :                 else
    1061               0 :                     osCommand += "NULL";
    1062                 :             }
    1063                 :             else
    1064                 :             {
    1065               0 :                 Oid     oid = GeometryToOID( poFeature->GetGeometryRef() );
    1066                 : 
    1067               0 :                 if( oid != 0 )
    1068                 :                 {
    1069               0 :                     osCommand += CPLString().Printf( "'%d' ", oid );
    1070                 :                 }
    1071                 :                 else
    1072               0 :                     osCommand += "NULL";
    1073                 :             }
    1074                 :         }
    1075                 :         else
    1076            1001 :             osCommand += "NULL";
    1077            1002 :         bNeedComma = TRUE;
    1078                 :     }
    1079            1002 :     else if( bHasPostGISGeometry || bHasPostGISGeography )
    1080                 :     {
    1081            1002 :         osCommand = osCommand + "\"" + pszGeomColumn + "\" = ";
    1082            1002 :         char    *pszWKT = NULL;
    1083                 : 
    1084            1002 :         if( poFeature->GetGeometryRef() != NULL )
    1085                 :         {
    1086               1 :             OGRGeometry *poGeom = (OGRGeometry *) poFeature->GetGeometryRef();
    1087                 : 
    1088               1 :             poGeom->closeRings();
    1089               1 :             poGeom->setCoordinateDimension( nCoordDimension );
    1090                 : 
    1091               1 :             poGeom->exportToWkt( &pszWKT );
    1092                 :         }
    1093                 : 
    1094            1002 :         if( pszWKT != NULL )
    1095                 :         {
    1096               1 :             if( bHasPostGISGeography )
    1097                 :                 osCommand +=
    1098                 :                     CPLString().Printf(
    1099               0 :                         "ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
    1100               1 :             else if( poDS->sPostGISVersion.nMajor >= 1 )
    1101                 :                 osCommand +=
    1102                 :                     CPLString().Printf(
    1103               1 :                         "GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
    1104                 :             else
    1105                 :                 osCommand += 
    1106                 :                     CPLString().Printf(
    1107               0 :                         "GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
    1108               1 :             OGRFree( pszWKT );
    1109                 :         }
    1110                 :         else
    1111            1001 :             osCommand += "NULL";
    1112                 : 
    1113            1002 :         bNeedComma = TRUE;
    1114                 :     }
    1115                 : 
    1116            4024 :     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
    1117                 :     {
    1118            2020 :         if( bNeedComma )
    1119            2020 :             osCommand += ", ";
    1120                 :         else
    1121               0 :             bNeedComma = TRUE;
    1122                 : 
    1123                 :         osCommand = osCommand 
    1124            2020 :             + "\"" + poFeatureDefn->GetFieldDefn(i)->GetNameRef() + "\" = ";
    1125                 : 
    1126            2020 :         if( !poFeature->IsFieldSet( i ) )
    1127                 :         {
    1128              12 :             osCommand += "NULL";
    1129                 :         }
    1130                 :         else
    1131                 :         {
    1132            2008 :             AppendFieldValue(hPGConn, osCommand, poFeature, i);
    1133                 :         }
    1134                 :     }
    1135                 : 
    1136                 :     /* Add the WHERE clause */
    1137            2004 :     osCommand += " WHERE ";
    1138            2004 :     osCommand = osCommand + "\"" + pszFIDColumn + "\" = ";
    1139            2004 :     osCommand += CPLString().Printf( "%ld ", poFeature->GetFID() );
    1140                 : 
    1141                 : /* -------------------------------------------------------------------- */
    1142                 : /*      Execute the update.                                             */
    1143                 : /* -------------------------------------------------------------------- */
    1144            2004 :     hResult = PQexec(hPGConn, osCommand);
    1145            2004 :     if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
    1146                 :     {
    1147                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1148                 :                   "UPDATE command for feature %ld failed.\n%s\nCommand: %s",
    1149               0 :                   poFeature->GetFID(), PQerrorMessage(hPGConn), osCommand.c_str() );
    1150                 : 
    1151               0 :         OGRPGClearResult( hResult );
    1152                 : 
    1153               0 :         poDS->SoftRollback();
    1154                 : 
    1155               0 :         return OGRERR_FAILURE;
    1156                 :     }
    1157                 : 
    1158            2004 :     OGRPGClearResult( hResult );
    1159                 : 
    1160            2004 :     return poDS->SoftCommit();
    1161                 : }
    1162                 : 
    1163                 : /************************************************************************/
    1164                 : /*                           CreateFeature()                            */
    1165                 : /************************************************************************/
    1166                 : 
    1167            2114 : OGRErr OGRPGTableLayer::CreateFeature( OGRFeature *poFeature )
    1168                 : { 
    1169            2114 :     if( NULL == poFeature )
    1170                 :     {
    1171                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1172               0 :                   "NULL pointer to OGRFeature passed to CreateFeature()." );
    1173               0 :         return OGRERR_FAILURE;
    1174                 :     }
    1175                 : 
    1176                 :     // We avoid testing the config option too often. 
    1177            2114 :     if( bUseCopy == USE_COPY_UNSET )
    1178              39 :         bUseCopy = CSLTestBoolean( CPLGetConfigOption( "PG_USE_COPY", "NO") );
    1179                 : 
    1180            2114 :     if( !bUseCopy )
    1181                 :     {
    1182            2092 :         return CreateFeatureViaInsert( poFeature );
    1183                 :     }
    1184                 :     else
    1185                 :     {
    1186              22 :         if ( !bCopyActive )
    1187               4 :             StartCopy();
    1188                 : 
    1189              22 :         return CreateFeatureViaCopy( poFeature );
    1190                 :     }
    1191                 : }
    1192                 : 
    1193                 : /************************************************************************/
    1194                 : /*                         OGRPGEscapeString( )                         */
    1195                 : /************************************************************************/
    1196                 : 
    1197                 : CPLString OGRPGEscapeString(PGconn *hPGConn,
    1198                 :                             const char* pszStrValue, int nMaxLength,
    1199             148 :                             const char* pszFieldName)
    1200                 : {
    1201             148 :     CPLString osCommand;
    1202                 : 
    1203                 :     /* We need to quote and escape string fields. */
    1204             148 :     osCommand += "'";
    1205                 : 
    1206             148 :     int nSrcLen = strlen(pszStrValue);
    1207             148 :     if (nMaxLength > 0 && nSrcLen > nMaxLength)
    1208                 :     {
    1209                 :         CPLDebug( "PG",
    1210                 :                   "Truncated %s field value, it was too long.",
    1211               2 :                   pszFieldName );
    1212               2 :         nSrcLen = nMaxLength;
    1213                 :         
    1214               4 :         while( nSrcLen > 0 && ((unsigned char *) pszStrValue)[nSrcLen-1] > 127 )
    1215                 :         {
    1216               0 :             CPLDebug( "PG", "Backup to start of multi-byte character." );
    1217               0 :             nSrcLen--;
    1218                 :         }
    1219                 :     }
    1220                 : 
    1221             148 :     char* pszDestStr = (char*)CPLMalloc(2 * nSrcLen + 1);
    1222                 : 
    1223                 :     /* -------------------------------------------------------------------- */
    1224                 :     /*  PQescapeStringConn was introduced in PostgreSQL security releases   */
    1225                 :     /*  8.1.4, 8.0.8, 7.4.13, 7.3.15                                        */
    1226                 :     /*  PG_HAS_PQESCAPESTRINGCONN is added by a test in 'configure'         */
    1227                 :     /*  so it is not set by default when building OGR for Win32             */
    1228                 :     /* -------------------------------------------------------------------- */
    1229                 : #if defined(PG_HAS_PQESCAPESTRINGCONN)
    1230                 :     int nError;
    1231             148 :     PQescapeStringConn (hPGConn, pszDestStr, pszStrValue, nSrcLen, &nError);
    1232             148 :     if (nError == 0)
    1233             148 :         osCommand += pszDestStr;
    1234                 :     else
    1235                 :         CPLError(CE_Warning, CPLE_AppDefined, 
    1236                 :                  "PQescapeString(): %s\n"
    1237                 :                  "  input: '%s'\n"
    1238                 :                  "    got: '%s'\n",
    1239                 :                  PQerrorMessage( hPGConn ),
    1240               0 :                  pszStrValue, pszDestStr );
    1241                 : #else
    1242                 :     PQescapeString(pszDestStr, pszStrValue, nSrcLen);
    1243                 :     osCommand += pszDestStr;
    1244                 : #endif
    1245             148 :     CPLFree(pszDestStr);
    1246                 : 
    1247             148 :     osCommand += "'";
    1248                 : 
    1249               0 :     return osCommand;
    1250                 : }
    1251                 : 
    1252                 : 
    1253                 : /************************************************************************/
    1254                 : /*                       OGRPGEscapeStringList( )                         */
    1255                 : /************************************************************************/
    1256                 : 
    1257                 : static CPLString OGRPGEscapeStringList(PGconn *hPGConn,
    1258              12 :                                        char** papszItems, int bForInsertOrUpdate)
    1259                 : {
    1260              12 :     int bFirstItem = TRUE;
    1261              12 :     CPLString osStr;
    1262              12 :     if (bForInsertOrUpdate)
    1263               6 :         osStr += "ARRAY[";
    1264                 :     else
    1265               6 :         osStr += "{";
    1266              48 :     while(*papszItems)
    1267                 :     {
    1268              24 :         if (!bFirstItem)
    1269                 :         {
    1270              12 :             osStr += ',';
    1271                 :         }
    1272                 : 
    1273              24 :         char* pszStr = *papszItems;
    1274              24 :         if (*pszStr != '\0')
    1275                 :         {
    1276              24 :             if (bForInsertOrUpdate)
    1277              12 :                 osStr += OGRPGEscapeString(hPGConn, pszStr, -1, "");
    1278                 :             else
    1279                 :             {
    1280              12 :                 osStr += '"';
    1281                 : 
    1282              44 :                 while(*pszStr)
    1283                 :                 {
    1284              20 :                     if (*pszStr == '"' )
    1285               0 :                         osStr += "\\";
    1286              20 :                     osStr += *pszStr;
    1287              20 :                     pszStr++;
    1288                 :                 }
    1289                 : 
    1290              12 :                 osStr += '"';
    1291                 :             }
    1292                 :         }
    1293                 :         else
    1294               0 :             osStr += "NULL";
    1295                 : 
    1296              24 :         bFirstItem = FALSE;
    1297                 : 
    1298              24 :         papszItems++;
    1299                 :     }
    1300              12 :     if (bForInsertOrUpdate)
    1301               6 :         osStr += "]";
    1302                 :     else
    1303               6 :         osStr += "}";
    1304               0 :     return osStr;
    1305                 : }
    1306                 : 
    1307                 : /************************************************************************/
    1308                 : /*                       CreateFeatureViaInsert()                       */
    1309                 : /************************************************************************/
    1310                 : 
    1311            2092 : OGRErr OGRPGTableLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
    1312                 : 
    1313                 : {
    1314            2092 :     PGconn              *hPGConn = poDS->GetPGConn();
    1315                 :     PGresult            *hResult;
    1316            2092 :     CPLString           osCommand;
    1317                 :     int                 i;
    1318            2092 :     int                 bNeedComma = FALSE;
    1319                 :     OGRErr              eErr;
    1320                 : 
    1321            2092 :     eErr = poDS->SoftStartTransaction();
    1322            2092 :     if( eErr != OGRERR_NONE )
    1323                 :     {
    1324               0 :         return eErr;
    1325                 :     }
    1326                 : 
    1327                 : /* -------------------------------------------------------------------- */
    1328                 : /*      Form the INSERT command.                                        */
    1329                 : /* -------------------------------------------------------------------- */
    1330            2092 :     osCommand.Printf( "INSERT INTO %s (", pszSqlTableName );
    1331                 : 
    1332            2092 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
    1333                 : 
    1334            2114 :     if( bHasWkb && poGeom != NULL )
    1335                 :     {
    1336              22 :         osCommand += "WKB_GEOMETRY ";
    1337              22 :         bNeedComma = TRUE;
    1338                 :     }
    1339            2070 :     else if( (bHasPostGISGeometry || bHasPostGISGeography) && poGeom != NULL )
    1340                 :     {
    1341              52 :         osCommand = osCommand + "\"" + pszGeomColumn + "\" ";
    1342              52 :         bNeedComma = TRUE;
    1343                 :     }
    1344                 : 
    1345            2092 :     if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != NULL )
    1346                 :     {
    1347               0 :         if( bNeedComma )
    1348               0 :             osCommand += ", ";
    1349                 :         
    1350               0 :         osCommand = osCommand + "\"" + pszFIDColumn + "\" ";
    1351               0 :         bNeedComma = TRUE;
    1352                 :     }
    1353                 : 
    1354            2092 :     int nFieldCount = poFeatureDefn->GetFieldCount();
    1355            4516 :     for( i = 0; i < nFieldCount; i++ )
    1356                 :     {
    1357            2424 :         if( !poFeature->IsFieldSet( i ) )
    1358             138 :             continue;
    1359                 : 
    1360            2286 :         if( !bNeedComma )
    1361            2018 :             bNeedComma = TRUE;
    1362                 :         else
    1363             268 :             osCommand += ", ";
    1364                 : 
    1365                 :         osCommand = osCommand 
    1366            2286 :             + "\"" + poFeatureDefn->GetFieldDefn(i)->GetNameRef() + "\"";
    1367                 :     }
    1368                 : 
    1369            2092 :     osCommand += ") VALUES (";
    1370                 : 
    1371                 :     /* Set the geometry */
    1372            2092 :     bNeedComma = poGeom != NULL;
    1373            2144 :     if( (bHasPostGISGeometry || bHasPostGISGeography) && poGeom != NULL)
    1374                 :     {
    1375              52 :         char    *pszWKT = NULL;
    1376                 :         
    1377              52 :         CheckGeomTypeCompatibility(poGeom);
    1378                 : 
    1379              52 :         poGeom->closeRings();
    1380              52 :         poGeom->setCoordinateDimension( nCoordDimension );
    1381                 : 
    1382              52 :         poGeom->exportToWkt( &pszWKT );
    1383                 : 
    1384              52 :         if( pszWKT != NULL )
    1385                 :         {
    1386              52 :             if( bHasPostGISGeography )
    1387                 :                 osCommand +=
    1388                 :                     CPLString().Printf(
    1389               0 :                         "ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
    1390              52 :             else if( poDS->sPostGISVersion.nMajor >= 1 )
    1391                 :                 osCommand +=
    1392                 :                     CPLString().Printf(
    1393              52 :                         "GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
    1394                 :             else
    1395                 :                 osCommand += 
    1396                 :                     CPLString().Printf(
    1397               0 :                         "GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
    1398              52 :             OGRFree( pszWKT );
    1399                 :         }
    1400                 :         else
    1401               0 :             osCommand += "''";
    1402                 :     }
    1403            2062 :     else if( bHasWkb && !bWkbAsOid && poGeom != NULL )
    1404                 :     {
    1405              22 :         char    *pszBytea = GeometryToBYTEA( poGeom );
    1406                 : 
    1407              22 :         if( pszBytea != NULL )
    1408                 :         {
    1409              22 :             osCommand = osCommand + "'" + pszBytea + "'";
    1410              22 :             CPLFree( pszBytea );
    1411                 :         }
    1412                 :         else
    1413               0 :             osCommand += "''";
    1414                 :     }
    1415            2018 :     else if( bHasWkb && bWkbAsOid && poGeom != NULL )
    1416                 :     {
    1417               0 :         Oid     oid = GeometryToOID( poGeom );
    1418                 : 
    1419               0 :         if( oid != 0 )
    1420                 :         {
    1421               0 :             osCommand += CPLString().Printf( "'%d' ", oid );
    1422                 :         }
    1423                 :         else
    1424               0 :             osCommand += "''";
    1425                 :     }
    1426                 : 
    1427                 :     /* Set the FID */
    1428            2092 :     if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != NULL )
    1429                 :     {
    1430               0 :         if( bNeedComma )
    1431               0 :             osCommand += ", ";
    1432               0 :         osCommand += CPLString().Printf( "%ld ", poFeature->GetFID() );
    1433               0 :         bNeedComma = TRUE;
    1434                 :     }
    1435                 : 
    1436                 : 
    1437            4516 :     for( i = 0; i < nFieldCount; i++ )
    1438                 :     {
    1439            2424 :         if( !poFeature->IsFieldSet( i ) )
    1440             138 :             continue;
    1441                 : 
    1442            2286 :         if( bNeedComma )
    1443             268 :             osCommand += ", ";
    1444                 :         else
    1445            2018 :             bNeedComma = TRUE;
    1446                 : 
    1447            2286 :         AppendFieldValue(hPGConn, osCommand, poFeature, i);
    1448                 :     }
    1449                 : 
    1450            2092 :     osCommand += ")";
    1451                 : 
    1452                 : /* -------------------------------------------------------------------- */
    1453                 : /*      Execute the insert.                                             */
    1454                 : /* -------------------------------------------------------------------- */
    1455            2092 :     hResult = PQexec(hPGConn, osCommand);
    1456            2092 :     if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
    1457                 :     {
    1458                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1459                 :                   "INSERT command for new feature failed.\n%s\nCommand: %s",
    1460               0 :                   PQerrorMessage(hPGConn), osCommand.c_str() );
    1461                 : 
    1462               0 :         OGRPGClearResult( hResult );
    1463                 : 
    1464               0 :         poDS->SoftRollback();
    1465                 : 
    1466               0 :         return OGRERR_FAILURE;
    1467                 :     }
    1468                 : 
    1469                 : #ifdef notdef
    1470                 :     /* Should we use this oid to get back the FID and assign back to the
    1471                 :        feature?  I think we are supposed to. */
    1472                 :     Oid nNewOID = PQoidValue( hResult );
    1473                 :     printf( "nNewOID = %d\n", (int) nNewOID );
    1474                 : #endif
    1475                 : 
    1476            2092 :     OGRPGClearResult( hResult );
    1477                 : 
    1478            2092 :     return poDS->SoftCommit();
    1479                 : }
    1480                 : 
    1481                 : /************************************************************************/
    1482                 : /*                        CreateFeatureViaCopy()                        */
    1483                 : /************************************************************************/
    1484                 : 
    1485              22 : OGRErr OGRPGTableLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
    1486                 : {
    1487              22 :     PGconn              *hPGConn = poDS->GetPGConn();
    1488              22 :     CPLString            osCommand;
    1489                 : 
    1490                 :     /* First process geometry */
    1491              22 :     OGRGeometry *poGeometry = (OGRGeometry *) poFeature->GetGeometryRef();
    1492                 :     
    1493              22 :     char *pszGeom = NULL;
    1494              22 :     if ( NULL != poGeometry && (bHasWkb || bHasPostGISGeometry || bHasPostGISGeography))
    1495                 :     {
    1496              22 :         poGeometry->closeRings();
    1497              22 :         poGeometry->setCoordinateDimension( nCoordDimension );
    1498                 :         
    1499              22 :         CheckGeomTypeCompatibility(poGeometry);
    1500                 : 
    1501              22 :         if (bHasWkb)
    1502              11 :             pszGeom = GeometryToBYTEA( poGeometry );
    1503                 :         else
    1504              11 :             pszGeom = GeometryToHex( poGeometry, nSRSId );
    1505                 :     }
    1506                 : 
    1507              22 :     if ( pszGeom )
    1508                 :     {
    1509                 :         osCommand += pszGeom,
    1510              22 :         CPLFree( pszGeom );
    1511                 :     }
    1512                 :     else
    1513                 :     {
    1514               0 :         osCommand = "\\N";
    1515                 :     }
    1516                 : 
    1517                 :     /* Next process the field id column */
    1518              22 :     if( bHasFid && poFeatureDefn->GetFieldIndex( pszFIDColumn ) != -1 )
    1519                 :     {
    1520               0 :         if (osCommand.size() > 0)
    1521               0 :             osCommand += "\t";
    1522                 :             
    1523                 :         /* Set the FID */
    1524               0 :         if( poFeature->GetFID() != OGRNullFID )
    1525                 :         {
    1526               0 :             osCommand += CPLString().Printf("%ld ", poFeature->GetFID());
    1527                 :         }
    1528                 :         else
    1529                 :         {
    1530               0 :             osCommand += "\\N" ;
    1531                 :         }
    1532                 :     }
    1533                 : 
    1534                 : 
    1535                 :     /* Now process the remaining fields */
    1536                 : 
    1537              22 :     int nFieldCount = poFeatureDefn->GetFieldCount();
    1538             150 :     for( int i = 0; i < nFieldCount;  i++ )
    1539                 :     {
    1540             128 :         const char *pszStrValue = poFeature->GetFieldAsString(i);
    1541             128 :         char *pszNeedToFree = NULL;
    1542                 : 
    1543             128 :         if (osCommand.size() > 0)
    1544             128 :             osCommand += "\t";
    1545                 :             
    1546             128 :         if( !poFeature->IsFieldSet( i ) )
    1547                 :         {
    1548              20 :             osCommand += "\\N" ;
    1549                 : 
    1550              20 :             continue;
    1551                 :         }
    1552                 : 
    1553             108 :         int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
    1554                 : 
    1555                 :         // We need special formatting for integer list values.
    1556             108 :         if( nOGRFieldType == OFTIntegerList )
    1557                 :         {
    1558               2 :             int nCount, nOff = 0, j;
    1559               2 :             const int *panItems = poFeature->GetFieldAsIntegerList(i,&nCount);
    1560                 : 
    1561               2 :             pszNeedToFree = (char *) CPLMalloc(nCount * 13 + 10);
    1562               2 :             strcpy( pszNeedToFree, "{" );
    1563               6 :             for( j = 0; j < nCount; j++ )
    1564                 :             {
    1565               4 :                 if( j != 0 )
    1566               2 :                     strcat( pszNeedToFree+nOff, "," );
    1567                 : 
    1568               4 :                 nOff += strlen(pszNeedToFree+nOff);
    1569               4 :                 sprintf( pszNeedToFree+nOff, "%d", panItems[j] );
    1570                 :             }
    1571               2 :             strcat( pszNeedToFree+nOff, "}" );
    1572               2 :             pszStrValue = pszNeedToFree;
    1573                 :         }
    1574                 : 
    1575                 :         // We need special formatting for real list values.
    1576             106 :         else if( nOGRFieldType == OFTRealList )
    1577                 :         {
    1578               4 :             int nCount, nOff = 0, j;
    1579               4 :             const double *padfItems =poFeature->GetFieldAsDoubleList(i,&nCount);
    1580                 : 
    1581               4 :             pszNeedToFree = (char *) CPLMalloc(nCount * 40 + 10);
    1582               4 :             strcpy( pszNeedToFree, "{" );
    1583              12 :             for( j = 0; j < nCount; j++ )
    1584                 :             {
    1585               8 :                 if( j != 0 )
    1586               4 :                     strcat( pszNeedToFree+nOff, "," );
    1587                 : 
    1588               8 :                 nOff += strlen(pszNeedToFree+nOff);
    1589               8 :                 sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
    1590                 :                 //Check for special values. They need to be quoted.
    1591               8 :                 if( strcmp( pszNeedToFree+nOff, "nan" ) == 0 )
    1592               0 :                     sprintf( pszNeedToFree+nOff, "'NaN'" );
    1593               8 :                 else if( strcmp( pszNeedToFree+nOff, "inf" ) == 0 )
    1594               0 :                     sprintf( pszNeedToFree+nOff, "'Infinity'" );
    1595               8 :                 else if( strcmp( pszNeedToFree+nOff, "-inf" ) == 0 )
    1596               0 :                     sprintf( pszNeedToFree+nOff, "'-Infinity'" );
    1597                 : 
    1598               8 :                 char* pszComma = strchr(pszNeedToFree+nOff, ',');
    1599               8 :                 if (pszComma)
    1600               0 :                     *pszComma = '.';
    1601                 :             }
    1602               4 :             strcat( pszNeedToFree+nOff, "}" );
    1603               4 :             pszStrValue = pszNeedToFree;
    1604                 :         }
    1605                 : 
    1606                 : 
    1607                 :         // We need special formatting for string list values.
    1608             102 :         else if( nOGRFieldType == OFTStringList )
    1609                 :         {
    1610               6 :             CPLString osStr;
    1611               6 :             char **papszItems = poFeature->GetFieldAsStringList(i);
    1612                 : 
    1613               6 :             pszStrValue = pszNeedToFree = CPLStrdup(OGRPGEscapeStringList(hPGConn, papszItems, FALSE));
    1614                 :         }
    1615                 : 
    1616                 :         // Binary formatting
    1617              96 :         else if( nOGRFieldType == OFTBinary )
    1618                 :         {
    1619               2 :             int nLen = 0;
    1620               2 :             GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
    1621               2 :             char* pszBytea = GByteArrayToBYTEA( pabyData, nLen);
    1622                 : 
    1623               2 :             pszStrValue = pszNeedToFree = pszBytea;
    1624                 :         }
    1625                 : 
    1626              94 :         else if( nOGRFieldType == OFTReal )
    1627                 :         {
    1628              28 :             char* pszComma = strchr((char*)pszStrValue, ',');
    1629              28 :             if (pszComma)
    1630               0 :                 *pszComma = '.';
    1631                 :             //Check for special values. They need to be quoted.
    1632              28 :             if( strcmp( pszStrValue, "nan" ) == 0 )
    1633               0 :                 pszStrValue = "'NaN'";
    1634              28 :             else if( strcmp( pszStrValue, "inf" ) == 0 )
    1635               0 :                 pszStrValue = "'Infinity'";
    1636              28 :             else if( strcmp( pszStrValue, "-inf" ) == 0 )
    1637               0 :                 pszStrValue = "'-Infinity'";
    1638                 :         }
    1639                 : 
    1640             150 :         if( nOGRFieldType != OFTIntegerList &&
    1641                 :             nOGRFieldType != OFTRealList &&
    1642                 :             nOGRFieldType != OFTInteger &&
    1643                 :             nOGRFieldType != OFTReal &&
    1644                 :             nOGRFieldType != OFTBinary )
    1645                 :         {
    1646                 :             int         iChar;
    1647                 : 
    1648             414 :             for( iChar = 0; pszStrValue[iChar] != '\0'; iChar++ )
    1649                 :             {
    1650             372 :                 if( poFeatureDefn->GetFieldDefn(i)->GetWidth() > 0
    1651                 :                     && iChar == poFeatureDefn->GetFieldDefn(i)->GetWidth() )
    1652                 :                 {
    1653                 :                     CPLDebug( "PG",
    1654                 :                               "Truncated %s field value, it was too long.",
    1655               0 :                               poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
    1656               0 :                     break;
    1657                 :                 }
    1658                 : 
    1659                 :                 /* Escape embedded \, \t, \n, \r since they will cause COPY
    1660                 :                    to misinterpret a line of text and thus abort */
    1661             372 :                 if( pszStrValue[iChar] == '\\' || 
    1662                 :                     pszStrValue[iChar] == '\t' || 
    1663                 :                     pszStrValue[iChar] == '\r' || 
    1664                 :                     pszStrValue[iChar] == '\n'   )
    1665                 :                 {
    1666               0 :                     osCommand += '\\';
    1667                 :                 }
    1668                 : 
    1669             372 :                 osCommand += pszStrValue[iChar];
    1670                 :             }
    1671                 :         }
    1672                 :         else
    1673                 :         {
    1674              66 :             osCommand += pszStrValue;
    1675                 :         }
    1676                 : 
    1677             108 :         if( pszNeedToFree )
    1678              14 :             CPLFree( pszNeedToFree );
    1679                 :     }
    1680                 : 
    1681                 :     /* Add end of line marker */
    1682              22 :     osCommand += "\n";
    1683                 : 
    1684                 : 
    1685                 :     /* ------------------------------------------------------------ */
    1686                 :     /*      Execute the copy.                                       */
    1687                 :     /* ------------------------------------------------------------ */
    1688                 : 
    1689              22 :     OGRErr result = OGRERR_NONE;
    1690                 : 
    1691                 :     /* This is for postgresql  7.4 and higher */
    1692                 : #if !defined(PG_PRE74)
    1693              22 :     int copyResult = PQputCopyData(hPGConn, osCommand.c_str(), strlen(osCommand.c_str()));
    1694                 :     //CPLDebug("PG", "PQputCopyData(%s)", osCommand.c_str());
    1695                 : 
    1696              22 :     switch (copyResult)
    1697                 :     {
    1698                 :     case 0:
    1699               0 :         CPLError( CE_Failure, CPLE_AppDefined, "Writing COPY data blocked.");
    1700               0 :         result = OGRERR_FAILURE;
    1701               0 :         break;
    1702                 :     case -1:
    1703               0 :         CPLError( CE_Failure, CPLE_AppDefined, "%s", PQerrorMessage(hPGConn) );
    1704               0 :         result = OGRERR_FAILURE;
    1705                 :         break;
    1706                 :     }
    1707                 : #else /* else defined(PG_PRE74) */
    1708                 :     int copyResult = PQputline(hPGConn, osCommand.c_str());
    1709                 : 
    1710                 :     if (copyResult == EOF)
    1711                 :     {
    1712                 :       CPLError( CE_Failure, CPLE_AppDefined, "Writing COPY data blocked.");
    1713                 :       result = OGRERR_FAILURE;
    1714                 :     }  
    1715                 : #endif /* end of defined(PG_PRE74) */
    1716                 : 
    1717              22 :     return result;
    1718                 : }
    1719                 : 
    1720                 : 
    1721                 : /************************************************************************/
    1722                 : /*                           TestCapability()                           */
    1723                 : /************************************************************************/
    1724                 : 
    1725              66 : int OGRPGTableLayer::TestCapability( const char * pszCap )
    1726                 : 
    1727                 : {
    1728              66 :     if ( bUpdateAccess )
    1729                 :     {
    1730              64 :         if( EQUAL(pszCap,OLCSequentialWrite) || EQUAL(pszCap,OLCCreateField) )
    1731               4 :             return TRUE;
    1732                 : 
    1733              60 :         else if( EQUAL(pszCap,OLCRandomWrite) )
    1734               2 :             return bHasFid;
    1735                 :     }
    1736                 : 
    1737              60 :     if( EQUAL(pszCap,OLCRandomRead) )
    1738               2 :         return bHasFid;
    1739                 : 
    1740              58 :     else if( EQUAL(pszCap,OLCFastFeatureCount) ||
    1741                 :              EQUAL(pszCap,OLCFastSetNextByIndex) )
    1742              46 :         return m_poFilterGeom == NULL || bHasPostGISGeometry || bHasPostGISGeography;
    1743                 : 
    1744              12 :     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
    1745               2 :         return bHasPostGISGeometry || bHasPostGISGeography;
    1746                 : 
    1747              10 :     else if( EQUAL(pszCap,OLCTransactions) )
    1748               2 :         return TRUE;
    1749                 : 
    1750               8 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
    1751               6 :         return bHasPostGISGeometry;
    1752                 : 
    1753               2 :     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
    1754               2 :         return TRUE;
    1755                 : 
    1756                 :     else
    1757               0 :         return FALSE;
    1758                 : }
    1759                 : 
    1760                 : /************************************************************************/
    1761                 : /*                            CreateField()                             */
    1762                 : /************************************************************************/
    1763                 : 
    1764             143 : OGRErr OGRPGTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
    1765                 : 
    1766                 : {
    1767             143 :     PGconn              *hPGConn = poDS->GetPGConn();
    1768             143 :     PGresult            *hResult = NULL;
    1769             143 :     CPLString           osCommand;
    1770                 :     char                szFieldType[256];
    1771             143 :     OGRFieldDefn        oField( poFieldIn );
    1772                 : 
    1773                 : /* -------------------------------------------------------------------- */
    1774                 : /*      Do we want to "launder" the column names into Postgres          */
    1775                 : /*      friendly format?                                                */
    1776                 : /* -------------------------------------------------------------------- */
    1777             143 :     if( bLaunderColumnNames )
    1778                 :     {
    1779             143 :         char    *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
    1780                 : 
    1781             143 :         oField.SetName( pszSafeName );
    1782             143 :         CPLFree( pszSafeName );
    1783                 : 
    1784             143 :         if( EQUAL(oField.GetNameRef(),"oid") )
    1785                 :         {
    1786                 :             CPLError( CE_Warning, CPLE_AppDefined,
    1787               0 :                       "Renaming field 'oid' to 'oid_' to avoid conflict with internal oid field." );
    1788               0 :             oField.SetName( "oid_" );
    1789                 :         }
    1790                 :     }
    1791                 : 
    1792                 : /* -------------------------------------------------------------------- */
    1793                 : /*      Work out the PostgreSQL type.                                   */
    1794                 : /* -------------------------------------------------------------------- */
    1795             143 :     if( oField.GetType() == OFTInteger )
    1796                 :     {
    1797              28 :         if( oField.GetWidth() > 0 && bPreservePrecision )
    1798              12 :             sprintf( szFieldType, "NUMERIC(%d,0)", oField.GetWidth() );
    1799                 :         else
    1800              16 :             strcpy( szFieldType, "INTEGER" );
    1801                 :     }
    1802             115 :     else if( oField.GetType() == OFTReal )
    1803                 :     {
    1804              32 :         if( oField.GetWidth() > 0 && oField.GetPrecision() > 0
    1805                 :             && bPreservePrecision )
    1806                 :             sprintf( szFieldType, "NUMERIC(%d,%d)",
    1807               7 :                      oField.GetWidth(), oField.GetPrecision() );
    1808                 :         else
    1809              25 :             strcpy( szFieldType, "FLOAT8" );
    1810                 :     }
    1811              83 :     else if( oField.GetType() == OFTString )
    1812                 :     {
    1813              31 :         if( oField.GetWidth() == 0 || !bPreservePrecision )
    1814              14 :             strcpy( szFieldType, "VARCHAR" );
    1815                 :         else
    1816              17 :             sprintf( szFieldType, "CHAR(%d)", oField.GetWidth() );
    1817                 :     }
    1818              52 :     else if( oField.GetType() == OFTIntegerList )
    1819                 :     {
    1820               4 :         strcpy( szFieldType, "INTEGER[]" );
    1821                 :     }
    1822              48 :     else if( oField.GetType() == OFTRealList )
    1823                 :     {
    1824              10 :         strcpy( szFieldType, "FLOAT8[]" );
    1825                 :     }
    1826              38 :     else if( oField.GetType() == OFTStringList )
    1827                 :     {
    1828              12 :         strcpy( szFieldType, "varchar[]" );
    1829                 :     }
    1830              26 :     else if( oField.GetType() == OFTDate )
    1831                 :     {
    1832               6 :         strcpy( szFieldType, "date" );
    1833                 :     }
    1834              20 :     else if( oField.GetType() == OFTTime )
    1835                 :     {
    1836               6 :         strcpy( szFieldType, "time" );
    1837                 :     }
    1838              14 :     else if( oField.GetType() == OFTDateTime )
    1839                 :     {
    1840              10 :         strcpy( szFieldType, "timestamp with time zone" );
    1841                 :     }
    1842               4 :     else if( oField.GetType() == OFTBinary )
    1843                 :     {
    1844               4 :         strcpy( szFieldType, "bytea" );
    1845                 :     }
    1846               0 :     else if( bApproxOK )
    1847                 :     {
    1848                 :         CPLError( CE_Warning, CPLE_NotSupported,
    1849                 :                   "Can't create field %s with type %s on PostgreSQL layers.  Creating as VARCHAR.",
    1850                 :                   oField.GetNameRef(),
    1851               0 :                   OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
    1852               0 :         strcpy( szFieldType, "VARCHAR" );
    1853                 :     }
    1854                 :     else
    1855                 :     {
    1856                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1857                 :                   "Can't create field %s with type %s on PostgreSQL layers.",
    1858                 :                   oField.GetNameRef(),
    1859               0 :                   OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
    1860                 : 
    1861               0 :         return OGRERR_FAILURE;
    1862                 :     }
    1863                 : 
    1864                 : /* -------------------------------------------------------------------- */
    1865                 : /*      Create the new field.                                           */
    1866                 : /* -------------------------------------------------------------------- */
    1867             143 :     poDS->FlushSoftTransaction();
    1868             143 :     hResult = PQexec(hPGConn, "BEGIN");
    1869             143 :     OGRPGClearResult( hResult );
    1870                 : 
    1871                 :     osCommand.Printf( "ALTER TABLE %s ADD COLUMN \"%s\" %s",
    1872             143 :                       pszSqlTableName, oField.GetNameRef(), szFieldType );
    1873             143 :     hResult = PQexec(hPGConn, osCommand);
    1874             143 :     if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
    1875                 :     {
    1876                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1877                 :                   "%s\n%s", 
    1878                 :                   osCommand.c_str(), 
    1879               0 :                   PQerrorMessage(hPGConn) );
    1880                 : 
    1881               0 :         OGRPGClearResult( hResult );
    1882                 : 
    1883               0 :         hResult = PQexec( hPGConn, "ROLLBACK" );
    1884               0 :         OGRPGClearResult( hResult );
    1885                 : 
    1886               0 :         return OGRERR_FAILURE;
    1887                 :     }
    1888                 : 
    1889             143 :     OGRPGClearResult( hResult );
    1890                 : 
    1891             143 :     hResult = PQexec(hPGConn, "COMMIT");
    1892             143 :     OGRPGClearResult( hResult );
    1893                 : 
    1894             143 :     poFeatureDefn->AddFieldDefn( &oField );
    1895                 : 
    1896             143 :     return OGRERR_NONE;
    1897                 : }
    1898                 : 
    1899                 : /************************************************************************/
    1900                 : /*                             GetFeature()                             */
    1901                 : /************************************************************************/
    1902                 : 
    1903              15 : OGRFeature *OGRPGTableLayer::GetFeature( long nFeatureId )
    1904                 : 
    1905                 : {
    1906              15 :     if( pszFIDColumn == NULL )
    1907               0 :         return OGRLayer::GetFeature( nFeatureId );
    1908                 : 
    1909                 : /* -------------------------------------------------------------------- */
    1910                 : /*      Discard any existing resultset.                                 */
    1911                 : /* -------------------------------------------------------------------- */
    1912              15 :     ResetReading();
    1913                 : 
    1914                 : /* -------------------------------------------------------------------- */
    1915                 : /*      Issue query for a single record.                                */
    1916                 : /* -------------------------------------------------------------------- */
    1917              15 :     OGRFeature  *poFeature = NULL;
    1918              15 :     PGresult    *hResult = NULL;
    1919              15 :     PGconn      *hPGConn = poDS->GetPGConn();
    1920              15 :     CPLString    osFieldList = BuildFields();
    1921              15 :     CPLString    osCommand;
    1922                 : 
    1923              15 :     poDS->FlushSoftTransaction();
    1924              15 :     poDS->SoftStartTransaction();
    1925                 : 
    1926                 :     osCommand.Printf(
    1927                 :              "DECLARE getfeaturecursor %s for "
    1928                 :              "SELECT %s FROM %s WHERE \"%s\" = %ld",
    1929                 :               ( poDS->bUseBinaryCursor ) ? "BINARY CURSOR" : "CURSOR",
    1930                 :              osFieldList.c_str(), pszSqlTableName, pszFIDColumn,
    1931              15 :              nFeatureId );
    1932                 : 
    1933              15 :     hResult = PQexec(hPGConn, osCommand.c_str() );
    1934                 : 
    1935              15 :     if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
    1936                 :     {
    1937              15 :         OGRPGClearResult( hResult );
    1938                 : 
    1939              15 :         hResult = PQexec(hPGConn, "FETCH ALL in getfeaturecursor" );
    1940                 : 
    1941              15 :         if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK )
    1942                 :         {
    1943              15 :             int nRows = PQntuples(hResult);
    1944              15 :             if (nRows > 0)
    1945                 :             {
    1946              13 :                 hCursorResult = hResult;
    1947              13 :                 CreateMapFromFieldNameToIndex();
    1948              13 :                 poFeature = RecordToFeature( 0 );
    1949              13 :                 hCursorResult = NULL;
    1950                 : 
    1951              13 :                 if (nRows > 1)
    1952                 :                 {
    1953                 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1954                 :                              "%d rows in response to the WHERE %s = %ld clause !",
    1955               0 :                              nRows, pszFIDColumn, nFeatureId );
    1956                 :                 }
    1957                 :             }
    1958                 :             else
    1959                 :             {
    1960                 :                  CPLError( CE_Failure, CPLE_AppDefined,
    1961               2 :                   "Attempt to read feature with unknown feature id (%ld).", nFeatureId );
    1962                 :             }
    1963                 :         }
    1964                 :     }
    1965                 : 
    1966                 : /* -------------------------------------------------------------------- */
    1967                 : /*      Cleanup                                                         */
    1968                 : /* -------------------------------------------------------------------- */
    1969              15 :     OGRPGClearResult( hResult );
    1970                 : 
    1971              15 :     hResult = PQexec(hPGConn, "CLOSE getfeaturecursor");
    1972              15 :     OGRPGClearResult( hResult );
    1973                 : 
    1974              15 :     poDS->FlushSoftTransaction();
    1975                 : 
    1976              15 :     return poFeature;
    1977                 : }
    1978                 : 
    1979                 : /************************************************************************/
    1980                 : /*                          GetFeatureCount()                           */
    1981                 : /************************************************************************/
    1982                 : 
    1983              38 : int OGRPGTableLayer::GetFeatureCount( int bForce )
    1984                 : 
    1985                 : {
    1986              38 :     if( TestCapability(OLCFastFeatureCount) == FALSE )
    1987               3 :         return OGRPGLayer::GetFeatureCount( bForce );
    1988                 : 
    1989                 : /* -------------------------------------------------------------------- */
    1990                 : /*      In theory it might be wise to cache this result, but it         */
    1991                 : /*      won't be trivial to work out the lifetime of the value.         */
    1992                 : /*      After all someone else could be adding records from another     */
    1993                 : /*      application when working against a database.                    */
    1994                 : /* -------------------------------------------------------------------- */
    1995              35 :     PGconn              *hPGConn = poDS->GetPGConn();
    1996              35 :     PGresult            *hResult = NULL;
    1997              35 :     CPLString           osCommand;
    1998              35 :     int                 nCount = 0;
    1999                 : 
    2000                 :     osCommand.Printf(
    2001                 :         "SELECT count(*) FROM %s %s",
    2002              35 :         pszSqlTableName, osWHERE.c_str() );
    2003                 : 
    2004              35 :     hResult = PQexec(hPGConn, osCommand);
    2005              35 :     if( hResult != NULL && PQresultStatus(hResult) == PGRES_TUPLES_OK )
    2006              35 :         nCount = atoi(PQgetvalue(hResult,0,0));
    2007                 :     else
    2008               0 :         CPLDebug( "PG", "%s; failed.", osCommand.c_str() );
    2009              35 :     OGRPGClearResult( hResult );
    2010                 : 
    2011              35 :     return nCount;
    2012                 : }
    2013                 : 
    2014                 : /************************************************************************/
    2015                 : /*                           GetSpatialRef()                            */
    2016                 : /*                                                                      */
    2017                 : /*      We override this to try and fetch the table SRID from the       */
    2018                 : /*      geometry_columns table if the srsid is -2 (meaning we           */
    2019                 : /*      haven't yet even looked for it).                                */
    2020                 : /************************************************************************/
    2021                 : 
    2022             218 : OGRSpatialReference *OGRPGTableLayer::GetSpatialRef()
    2023                 : 
    2024                 : {
    2025             218 :     if( nSRSId == -2 )
    2026                 :     {
    2027             218 :         PGconn      *hPGConn = poDS->GetPGConn();
    2028             218 :         PGresult    *hResult = NULL;
    2029             218 :         CPLString    osCommand;
    2030                 : 
    2031             218 :         nSRSId = -1;
    2032                 : 
    2033             218 :         poDS->SoftStartTransaction();
    2034                 : 
    2035             218 :         if (bHasPostGISGeography)
    2036                 :         {
    2037                 :             osCommand.Printf(
    2038                 :                      "SELECT srid FROM geography_columns "
    2039                 :                      "WHERE f_table_name = '%s'",
    2040               0 :                      (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName);
    2041                 : 
    2042               0 :             if (pszGeomColumn)
    2043                 :             {
    2044               0 :                 osCommand += CPLString().Printf(" AND f_geography_column = '%s'", pszGeomColumn);
    2045                 :             }
    2046                 :         }
    2047                 :         else
    2048                 :         {
    2049                 :             osCommand.Printf(
    2050                 :                      "SELECT srid FROM geometry_columns "
    2051                 :                      "WHERE f_table_name = '%s'",
    2052             218 :                      (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName);
    2053                 : 
    2054             218 :             if (pszGeomColumn)
    2055                 :             {
    2056             210 :                 osCommand += CPLString().Printf(" AND f_geometry_column = '%s'", pszGeomColumn);
    2057                 :             }
    2058                 :         }
    2059                 : 
    2060             218 :         if (pszSchemaName)
    2061                 :         {
    2062             218 :             osCommand += CPLString().Printf(" AND f_table_schema = '%s'", pszSchemaName);
    2063                 :         }
    2064                 : 
    2065             218 :         hResult = PQexec(hPGConn, osCommand.c_str() );
    2066                 : 
    2067             218 :         if( hResult
    2068                 :             && PQresultStatus(hResult) == PGRES_TUPLES_OK
    2069                 :             && PQntuples(hResult) == 1 )
    2070                 :         {
    2071               1 :             nSRSId = atoi(PQgetvalue(hResult,0,0));
    2072                 :         }
    2073                 : 
    2074             218 :         OGRPGClearResult( hResult );
    2075                 : 
    2076             218 :         poDS->SoftCommit();
    2077                 :     }
    2078                 : 
    2079             218 :     return OGRPGLayer::GetSpatialRef();
    2080                 : }
    2081                 : 
    2082                 : /************************************************************************/
    2083                 : /*                             GetExtent()                              */
    2084                 : /*                                                                      */
    2085                 : /*      For PostGIS use internal Extend(geometry) function              */
    2086                 : /*      in other cases we use standard OGRLayer::GetExtent()            */
    2087                 : /************************************************************************/
    2088                 : 
    2089               2 : OGRErr OGRPGTableLayer::GetExtent( OGREnvelope *psExtent, int bForce )
    2090                 : {
    2091               2 :     CPLString   osCommand;
    2092                 : 
    2093               2 :     if ( TestCapability(OLCFastGetExtent) )
    2094                 :     {
    2095                 :         osCommand.Printf( "SELECT Extent(\"%s\") FROM %s", 
    2096               1 :                           pszGeomColumn, pszSqlTableName );
    2097                 :     }
    2098               1 :     else if ( bHasPostGISGeography )
    2099                 :     {
    2100                 :         /* Probably not very efficient, but more efficient than client-side implementation */
    2101                 :         osCommand.Printf( "SELECT Extent(ST_GeomFromWKB(ST_AsBinary(\"%s\"))) FROM %s", 
    2102               0 :                           pszGeomColumn, pszSqlTableName );
    2103                 :     }
    2104                 : 
    2105               2 :     return RunGetExtentRequest(psExtent, bForce, osCommand);
    2106                 : }
    2107                 : 
    2108                 : /************************************************************************/
    2109                 : /*                             StartCopy()                              */
    2110                 : /************************************************************************/
    2111                 : 
    2112               4 : OGRErr OGRPGTableLayer::StartCopy()
    2113                 : 
    2114                 : {
    2115               4 :     OGRErr result = OGRERR_NONE;
    2116                 : 
    2117                 :     /* Tell the datasource we are now planning to copy data */
    2118               4 :     poDS->StartCopy( this ); 
    2119                 : 
    2120               4 :     CPLString osFields = BuildCopyFields();
    2121                 : 
    2122               4 :     int size = strlen(osFields) +  strlen(pszSqlTableName) + 100;
    2123               4 :     char *pszCommand = (char *) CPLMalloc(size);
    2124                 : 
    2125                 :     sprintf( pszCommand,
    2126                 :              "COPY %s (%s) FROM STDIN;",
    2127               4 :              pszSqlTableName, osFields.c_str() );
    2128                 : 
    2129               4 :     PGconn *hPGConn = poDS->GetPGConn();
    2130               4 :     PGresult *hResult = PQexec(hPGConn, pszCommand);
    2131                 : 
    2132               4 :     if ( !hResult || (PQresultStatus(hResult) != PGRES_COPY_IN))
    2133                 :     {
    2134                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2135               0 :                   "%s", PQerrorMessage(hPGConn) );
    2136               0 :         result = OGRERR_FAILURE;
    2137                 :     }
    2138                 :     else
    2139               4 :         bCopyActive = TRUE;
    2140                 : 
    2141               4 :     OGRPGClearResult( hResult );
    2142               4 :     CPLFree( pszCommand );
    2143                 : 
    2144               4 :     return OGRERR_NONE;
    2145                 : }
    2146                 : 
    2147                 : /************************************************************************/
    2148                 : /*                              EndCopy()                               */
    2149                 : /************************************************************************/
    2150                 : 
    2151            1541 : OGRErr OGRPGTableLayer::EndCopy()
    2152                 : 
    2153                 : {
    2154            1541 :     if( !bCopyActive )
    2155            1537 :         return OGRERR_NONE;
    2156                 : 
    2157                 :     /* This method is called from the datasource when
    2158                 :        a COPY operation is ended */
    2159               4 :     OGRErr result = OGRERR_NONE;
    2160                 : 
    2161               4 :     PGconn *hPGConn = poDS->GetPGConn();
    2162               4 :     CPLDebug( "PG", "PQputCopyEnd()" );
    2163                 : 
    2164               4 :     bCopyActive = FALSE;
    2165                 : 
    2166                 :     /* This is for postgresql 7.4 and higher */
    2167                 : #if !defined(PG_PRE74)
    2168               4 :     int copyResult = PQputCopyEnd(hPGConn, NULL);
    2169                 : 
    2170               4 :     switch (copyResult)
    2171                 :     {
    2172                 :       case 0:
    2173               0 :         CPLError( CE_Failure, CPLE_AppDefined, "Writing COPY data blocked.");
    2174               0 :         result = OGRERR_FAILURE;
    2175               0 :         break;
    2176                 :       case -1:
    2177               0 :         CPLError( CE_Failure, CPLE_AppDefined, "%s", PQerrorMessage(hPGConn) );
    2178               0 :         result = OGRERR_FAILURE;
    2179                 :         break;
    2180                 :     }
    2181                 : 
    2182                 : #else /* defined(PG_PRE74) */
    2183                 :     PQputline(hPGConn, "\\.\n");
    2184                 :     int copyResult = PQendcopy(hPGConn);
    2185                 : 
    2186                 :     if (copyResult != 0)
    2187                 :     {
    2188                 :       CPLError( CE_Failure, CPLE_AppDefined, "%s", PQerrorMessage(hPGConn) );
    2189                 :       result = OGRERR_FAILURE;
    2190                 :     }
    2191                 : #endif /* defined(PG_PRE74) */
    2192                 : 
    2193                 :     /* Now check the results of the copy */
    2194               4 :     PGresult * hResult = PQgetResult( hPGConn );
    2195                 : 
    2196               4 :     if( hResult && PQresultStatus(hResult) != PGRES_COMMAND_OK )
    2197                 :     {
    2198                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2199                 :                   "COPY statement failed.\n%s",
    2200               0 :                   PQerrorMessage(hPGConn) );
    2201                 : 
    2202               0 :         result = OGRERR_FAILURE;
    2203                 :     }
    2204                 : 
    2205               4 :     OGRPGClearResult( hResult );
    2206                 : 
    2207               4 :     bUseCopy = USE_COPY_UNSET;
    2208                 : 
    2209               4 :     return result;
    2210                 : }
    2211                 : 
    2212                 : /************************************************************************/
    2213                 : /*                          BuildCopyFields()                           */
    2214                 : /************************************************************************/
    2215                 : 
    2216               4 : CPLString OGRPGTableLayer::BuildCopyFields()
    2217                 : {
    2218               4 :     int     i = 0;
    2219               4 :     CPLString osFieldList;
    2220                 : 
    2221               4 :     if( bHasFid && poFeatureDefn->GetFieldIndex( pszFIDColumn ) != -1 )
    2222                 :     {
    2223               0 :         osFieldList += "\"";
    2224               0 :         osFieldList += pszFIDColumn;
    2225               0 :         osFieldList += "\"";
    2226                 :     }
    2227                 : 
    2228               4 :     if( pszGeomColumn )
    2229                 :     {
    2230               4 :         if( strlen(osFieldList) > 0 )
    2231               0 :             osFieldList += ", ";
    2232                 : 
    2233               4 :         osFieldList += "\"";
    2234               4 :         osFieldList += pszGeomColumn;
    2235               4 :         osFieldList += "\"";
    2236                 :     }
    2237                 : 
    2238              60 :     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
    2239                 :     {
    2240              56 :         const char *pszName = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
    2241                 : 
    2242              56 :         if( strlen(osFieldList) > 0 )
    2243              56 :             osFieldList += ", ";
    2244                 : 
    2245              56 :         osFieldList += "\"";
    2246              56 :         osFieldList += pszName;
    2247              56 :         osFieldList += "\"" ;
    2248                 :     }
    2249                 : 
    2250               0 :     return osFieldList;
    2251                 : }
    2252                 : 
    2253                 : /************************************************************************/
    2254                 : /*                    CheckGeomTypeCompatibility()                      */
    2255                 : /************************************************************************/
    2256                 : 
    2257              74 : void OGRPGTableLayer::CheckGeomTypeCompatibility(OGRGeometry* poGeom)
    2258                 : {
    2259              74 :     if (bHasWarnedIncompatibleGeom)
    2260               0 :         return;
    2261                 :         
    2262              74 :     OGRwkbGeometryType eFlatLayerGeomType = wkbFlatten(poFeatureDefn->GetGeomType());
    2263              74 :     OGRwkbGeometryType eFlatGeomType = wkbFlatten(poGeom->getGeometryType());
    2264              74 :     if (eFlatLayerGeomType == wkbUnknown)
    2265              44 :         return;
    2266                 : 
    2267              30 :     if (eFlatLayerGeomType == wkbGeometryCollection)
    2268                 :         bHasWarnedIncompatibleGeom = eFlatGeomType != wkbMultiPoint &&
    2269                 :                                      eFlatGeomType != wkbMultiLineString &&
    2270                 :                                      eFlatGeomType != wkbMultiPolygon &&
    2271               0 :                                      eFlatGeomType != wkbGeometryCollection;
    2272                 :     else
    2273              30 :         bHasWarnedIncompatibleGeom = (eFlatGeomType != eFlatLayerGeomType);
    2274                 :     
    2275              30 :     if (bHasWarnedIncompatibleGeom)
    2276                 :     {
    2277                 :         CPLError(CE_Warning, CPLE_AppDefined,
    2278                 :                  "Geometry to be inserted is of type %s, whereas the layer geometry type is %s.\n"
    2279                 :                  "Insertion is likely to fail",
    2280                 :                  OGRGeometryTypeToName(poGeom->getGeometryType()), 
    2281               0 :                  OGRGeometryTypeToName(poFeatureDefn->GetGeomType()));
    2282                 :     }
    2283                 : }

Generated by: LTP GCOV extension version 1.5