LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpgtablelayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1117 931 83.3 %
Date: 2011-12-18 Functions: 39 36 92.3 %

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

Generated by: LCOV version 1.7