LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpgtablelayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 900 765 85.0 %
Date: 2010-01-09 Functions: 29 29 100.0 %

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

Generated by: LCOV version 1.7