~ubuntu-branches/debian/sid/gdal/sid

« back to all changes in this revision

Viewing changes to ogr/ogrsf_frmts/pg/ogrpgtablelayer.cpp

  • Committer: Package Import Robot
  • Author(s): Francesco Paolo Lovergine
  • Date: 2012-05-07 15:04:42 UTC
  • mfrom: (5.5.16 experimental)
  • Revision ID: package-import@ubuntu.com-20120507150442-2eks97loeh6rq005
Tags: 1.9.0-1
* Ready for sid, starting transition.
* All symfiles updated to latest builds.
* Added dh_numpy call in debian/rules to depend on numpy ABI.
* Policy bumped to 3.9.3, no changes required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/******************************************************************************
2
 
 * $Id: ogrpgtablelayer.cpp 19975 2010-07-05 18:34:02Z rouault $
 
2
 * $Id: ogrpgtablelayer.cpp 23674 2012-01-01 14:32:18Z rouault $
3
3
 *
4
4
 * Project:  OpenGIS Simple Features Reference Implementation
5
5
 * Purpose:  Implements OGRPGTableLayer class, access to an existing table.
28
28
 ****************************************************************************/
29
29
 
30
30
#include "ogr_pg.h"
31
 
#include "ogrpgutility.h"
32
31
#include "cpl_conv.h"
33
32
#include "cpl_string.h"
34
33
#include "cpl_error.h"
35
34
 
36
 
CPL_CVSID("$Id: ogrpgtablelayer.cpp 19975 2010-07-05 18:34:02Z rouault $");
 
35
#define PQexec this_is_an_error
 
36
 
 
37
CPL_CVSID("$Id: ogrpgtablelayer.cpp 23674 2012-01-01 14:32:18Z rouault $");
37
38
 
38
39
#define USE_COPY_UNSET  -10
39
40
static CPLString OGRPGEscapeStringList(PGconn *hPGConn,
62
63
    iNextShapeId = 0;
63
64
 
64
65
    nSRSId = nSRSIdIn;
 
66
    nGeomType = wkbUnknown;
 
67
    bGeometryInformationSet = FALSE;
65
68
 
66
69
    bLaunderColumnNames = TRUE;
 
70
    bPreservePrecision = TRUE;
67
71
    bCopyActive = FALSE;
68
72
    bUseCopy = USE_COPY_UNSET;  // unknown
69
73
 
70
74
    pszTableName = CPLStrdup( pszTableNameIn );
71
 
    pszSchemaName = NULL; // set in ReadTableDefinition
72
 
    pszSqlTableName = NULL; //set in ReadTableDefinition
 
75
    if (pszGeomColumnIn)
 
76
        pszGeomColumn = CPLStrdup(pszGeomColumnIn);
 
77
    if (pszSchemaNameIn)
 
78
        pszSchemaName = CPLStrdup( pszSchemaNameIn );
 
79
    else if (strlen(osCurrentSchema))
 
80
        pszSchemaName = CPLStrdup( osCurrentSchema );
 
81
    else
 
82
        pszSchemaName = NULL;
 
83
 
73
84
    pszSqlGeomParentTableName = NULL;
74
85
 
75
 
    poFeatureDefn = ReadTableDefinition( osCurrentSchema,
76
 
                                         pszTableName,
77
 
                                         pszSchemaNameIn,
78
 
                                         pszGeomColumnIn,
79
 
                                         bAdvertizeGeomColumn );
80
 
 
81
 
    if( poFeatureDefn )
82
 
    {
83
 
        ResetReading();
84
 
        
85
 
        // check SRID if it's necessary
86
 
        if( nSRSId == -2 )
87
 
            GetSpatialRef();
88
 
    }
89
 
    
90
86
    bHasWarnedIncompatibleGeom = FALSE;
 
87
    bHasWarnedAlreadySetFID = FALSE;
 
88
 
 
89
    /* Just in provision for people yelling about broken backward compatibility ... */
 
90
    bRetrieveFID = CSLTestBoolean(CPLGetConfigOption("OGR_PG_RETRIEVE_FID", "TRUE"));
 
91
 
 
92
/* -------------------------------------------------------------------- */
 
93
/*      Build the layer defn name.                                      */
 
94
/* -------------------------------------------------------------------- */
 
95
    if ( pszSchemaNameIn && osCurrentSchema != pszSchemaNameIn )
 
96
    {
 
97
        /* For backwards compatibility, don't report the geometry column name */
 
98
        /* if it's wkb_geometry */
 
99
        if (bAdvertizeGeomColumn && pszGeomColumnIn)
 
100
            osDefnName.Printf( "%s.%s(%s)", pszSchemaNameIn, pszTableName, pszGeomColumnIn );
 
101
        else
 
102
            osDefnName.Printf("%s.%s", pszSchemaNameIn, pszTableName );
 
103
        pszSqlTableName = CPLStrdup(CPLString().Printf("%s.%s",
 
104
                               OGRPGEscapeColumnName(pszSchemaNameIn).c_str(),
 
105
                               OGRPGEscapeColumnName(pszTableName).c_str() ));
 
106
    }
 
107
    else
 
108
    {
 
109
        //no prefix for current_schema in layer name, for backwards compatibility
 
110
        /* For backwards compatibility, don't report the geometry column name */
 
111
        /* if it's wkb_geometry */
 
112
        if (bAdvertizeGeomColumn && pszGeomColumnIn)
 
113
            osDefnName.Printf( "%s(%s)", pszTableName, pszGeomColumnIn );
 
114
        else
 
115
            osDefnName = pszTableName;
 
116
        pszSqlTableName = CPLStrdup(OGRPGEscapeColumnName(pszTableName));
 
117
    }
 
118
 
 
119
    osPrimaryKey = CPLGetConfigOption( "PGSQL_OGR_FID", "ogc_fid" );
91
120
}
92
121
 
93
122
//************************************************************************/
105
134
}
106
135
 
107
136
/************************************************************************/
 
137
/*                      SetGeometryInformation()                        */
 
138
/************************************************************************/
 
139
 
 
140
void  OGRPGTableLayer::SetGeometryInformation(const char* pszType,
 
141
                                               int nCoordDimension,
 
142
                                               int nSRID,
 
143
                                               PostgisType ePostgisType)
 
144
{
 
145
    if (pszType == NULL || nCoordDimension == 0 || nSRID == UNDETERMINED_SRID ||
 
146
        ePostgisType == GEOM_TYPE_UNKNOWN)
 
147
        return;
 
148
 
 
149
    bGeometryInformationSet = TRUE;
 
150
 
 
151
    nGeomType = OGRFromOGCGeomType(pszType);
 
152
 
 
153
    this->nCoordDimension = nCoordDimension;
 
154
    this->nSRSId = nSRID;
 
155
 
 
156
    if( nCoordDimension == 3 && nGeomType != wkbUnknown )
 
157
        nGeomType = (OGRwkbGeometryType) (nGeomType | wkb25DBit);
 
158
 
 
159
    if( ePostgisType == GEOM_TYPE_GEOMETRY)
 
160
        bHasPostGISGeometry = TRUE;
 
161
    else if( ePostgisType == GEOM_TYPE_GEOGRAPHY)
 
162
        bHasPostGISGeography = TRUE;
 
163
 
 
164
    CPLDebug("PG","Layer '%s' geometry type: %s:%s, Dim=%d",
 
165
                pszTableName, pszType, OGRGeometryTypeToName(nGeomType),
 
166
                nCoordDimension );
 
167
}
 
168
 
 
169
/************************************************************************/
 
170
/*                            GetGeomType()                             */
 
171
/************************************************************************/
 
172
 
 
173
OGRwkbGeometryType  OGRPGTableLayer::GetGeomType()
 
174
{
 
175
    if (bGeometryInformationSet)
 
176
        return nGeomType;
 
177
 
 
178
    return GetLayerDefn()->GetGeomType();
 
179
}
 
180
    
 
181
/************************************************************************/
108
182
/*                        ReadTableDefinition()                         */
109
183
/*                                                                      */
110
184
/*      Build a schema from the named table.  Done by querying the      */
111
185
/*      catalog.                                                        */
112
186
/************************************************************************/
113
187
 
114
 
OGRFeatureDefn *OGRPGTableLayer::ReadTableDefinition( CPLString& osCurrentSchema,
115
 
                                                      const char * pszTableIn,
116
 
                                                      const char * pszSchemaNameIn,
117
 
                                                      const char * pszGeomColumnIn,
118
 
                                                      int bAdvertizeGeomColumn)
 
188
OGRFeatureDefn *OGRPGTableLayer::ReadTableDefinition()
119
189
 
120
190
{
121
191
    PGresult            *hResult;
122
192
    CPLString           osCommand;
123
 
    CPLString           osPrimaryKey;
124
193
    PGconn              *hPGConn = poDS->GetPGConn();
125
194
 
126
195
    poDS->FlushSoftTransaction();
127
196
 
128
 
    /* -------------------------------------------- */
129
 
    /*          Detect table primary key            */
130
 
    /* -------------------------------------------- */
131
 
 
132
 
    /* -------------------------------------------- */
133
 
    /*          Check config options                */
134
 
    /* -------------------------------------------- */
135
 
    osPrimaryKey = CPLGetConfigOption( "PGSQL_OGR_FID", "ogc_fid" );
136
 
 
137
 
    if (pszSchemaNameIn)
138
 
      pszSchemaName = CPLStrdup( pszSchemaNameIn );
139
 
    else if (strlen(osCurrentSchema))
140
 
      pszSchemaName = CPLStrdup( osCurrentSchema );
141
 
 
142
197
    CPLString osSchemaClause;
143
198
    if( pszSchemaName )
144
199
        osSchemaClause.Printf("AND n.nspname='%s'", pszSchemaName);
149
204
    else
150
205
        pszTypnameEqualsAnyClause = "ANY(ARRAY['int2','int4','serial'])";
151
206
 
 
207
    CPLString osEscapedTableNameSingleQuote = OGRPGEscapeString(hPGConn, pszTableName, -1, "");
 
208
    const char* pszEscapedTableNameSingleQuote = osEscapedTableNameSingleQuote.c_str();
 
209
 
152
210
    /* See #1889 for why we don't use 'AND a.attnum = ANY(i.indkey)' */
153
211
    osCommand.Printf("SELECT a.attname, a.attnum, t.typname, "
154
212
              "t.typname = %s AS isfid "
156
214
              "WHERE a.attnum > 0 AND a.attrelid = c.oid "
157
215
              "AND a.atttypid = t.oid AND c.relnamespace = n.oid "
158
216
              "AND c.oid = i.indrelid AND i.indisprimary = 't' "
159
 
              "AND t.typname !~ '^geom' AND c.relname = '%s' "
 
217
              "AND t.typname !~ '^geom' AND c.relname = %s "
160
218
              "AND (i.indkey[0]=a.attnum OR i.indkey[1]=a.attnum OR i.indkey[2]=a.attnum "
161
219
              "OR i.indkey[3]=a.attnum OR i.indkey[4]=a.attnum OR i.indkey[5]=a.attnum "
162
220
              "OR i.indkey[6]=a.attnum OR i.indkey[7]=a.attnum OR i.indkey[8]=a.attnum "
163
221
              "OR i.indkey[9]=a.attnum) %s ORDER BY a.attnum",
164
 
              pszTypnameEqualsAnyClause, pszTableIn, osSchemaClause.c_str() );
 
222
              pszTypnameEqualsAnyClause, pszEscapedTableNameSingleQuote, osSchemaClause.c_str() );
165
223
     
166
 
    hResult = PQexec(hPGConn, osCommand.c_str() );
 
224
    hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
167
225
 
168
226
    if ( hResult && PGRES_TUPLES_OK == PQresultStatus(hResult) )
169
227
    {
181
239
        {
182
240
            CPLError( CE_Warning, CPLE_AppDefined,
183
241
                      "Multi-column primary key in \'%s\' detected but not supported.",
184
 
                      pszTableIn );
 
242
                      pszTableName );
185
243
        }
186
244
 
187
245
        OGRPGClearResult( hResult );
196
254
/* -------------------------------------------------------------------- */
197
255
/*      Fire off commands to get back the columns of the table.          */
198
256
/* -------------------------------------------------------------------- */
199
 
    hResult = PQexec(hPGConn, "BEGIN");
 
257
    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
200
258
 
201
259
    if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
202
260
    {
205
263
        osCommand.Printf(
206
264
                 "DECLARE mycursor CURSOR for "
207
265
                 "SELECT DISTINCT a.attname, t.typname, a.attlen,"
208
 
                 "       format_type(a.atttypid,a.atttypmod) "
 
266
                 "       format_type(a.atttypid,a.atttypmod), a.attnum "
209
267
                 "FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n "
210
 
                 "WHERE c.relname = '%s' "
 
268
                 "WHERE c.relname = %s "
211
269
                 "AND a.attnum > 0 AND a.attrelid = c.oid "
212
270
                 "AND a.atttypid = t.oid "
213
271
                 "AND c.relnamespace=n.oid "
214
 
                 "%s",
215
 
                 pszTableIn, osSchemaClause.c_str());
 
272
                 "%s"
 
273
                 "ORDER BY a.attnum",
 
274
                 pszEscapedTableNameSingleQuote, osSchemaClause.c_str());
216
275
 
217
 
        hResult = PQexec(hPGConn, osCommand.c_str() );
 
276
        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
218
277
    }
219
278
 
220
279
    if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
221
280
    {
222
281
        OGRPGClearResult( hResult );
223
 
        hResult = PQexec(hPGConn, "FETCH ALL in mycursor" );
 
282
        hResult = OGRPG_PQexec(hPGConn, "FETCH ALL in mycursor" );
224
283
    }
225
284
 
226
285
    if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
236
295
    {
237
296
        OGRPGClearResult( hResult );
238
297
 
239
 
        hResult = PQexec(hPGConn, "CLOSE mycursor");
 
298
        hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
240
299
        OGRPGClearResult( hResult );
241
300
 
242
 
        hResult = PQexec(hPGConn, "COMMIT");
 
301
        hResult = OGRPG_PQexec(hPGConn, "COMMIT");
243
302
        OGRPGClearResult( hResult );
244
303
 
245
304
        CPLError( CE_Failure, CPLE_AppDefined,
246
305
                  "No field definitions found for '%s', is it a table?",
247
 
                  pszTableIn );
 
306
                  pszTableName );
248
307
        return NULL;
249
308
    }
250
309
 
251
310
/* -------------------------------------------------------------------- */
252
311
/*      Parse the returned table information.                           */
253
312
/* -------------------------------------------------------------------- */
254
 
    CPLString osDefnName;
255
 
    if ( pszSchemaNameIn && osCurrentSchema != pszSchemaNameIn )
256
 
    {
257
 
        /* For backwards compatibility, don't report the geometry column name */
258
 
        /* if it's wkb_geometry */
259
 
        if (bAdvertizeGeomColumn && pszGeomColumnIn)
260
 
            osDefnName.Printf( "%s.%s(%s)", pszSchemaNameIn, pszTableIn, pszGeomColumnIn );
261
 
        else
262
 
            osDefnName.Printf("%s.%s", pszSchemaNameIn, pszTableIn );
263
 
        pszSqlTableName = CPLStrdup(CPLString().Printf("\"%s\".\"%s\"", pszSchemaNameIn, pszTableIn ));
264
 
    }
265
 
    else
266
 
    {   
267
 
        //no prefix for current_schema in layer name, for backwards compatibility
268
 
        /* For backwards compatibility, don't report the geometry column name */
269
 
        /* if it's wkb_geometry */
270
 
        if (bAdvertizeGeomColumn && pszGeomColumnIn)
271
 
            osDefnName.Printf( "%s(%s)", pszTableIn, pszGeomColumnIn );
272
 
        else
273
 
            osDefnName = pszTableIn;
274
 
        pszSqlTableName = CPLStrdup(CPLString().Printf("\"%s\"", pszTableIn ));
275
 
    }
276
 
 
277
313
    OGRFeatureDefn *poDefn = new OGRFeatureDefn( osDefnName );
278
314
    int            iRecord;
279
315
 
280
316
    poDefn->Reference();
281
 
    poDefn->SetGeomType( wkbNone );
282
 
    if (pszGeomColumnIn)
283
 
      pszGeomColumn = CPLStrdup(pszGeomColumnIn);
284
317
 
285
318
    for( iRecord = 0; iRecord < PQntuples(hResult); iRecord++ )
286
319
    {
291
324
        pszType = PQgetvalue(hResult, iRecord, 1 );
292
325
        pszFormatType = PQgetvalue(hResult,iRecord,3);
293
326
 
294
 
        /* TODO: Add detection of other primary key to use as FID */
295
327
        if( EQUAL(oField.GetNameRef(),osPrimaryKey) )
296
328
        {
297
329
            bHasFid = TRUE;
298
330
            pszFIDColumn = CPLStrdup(oField.GetNameRef());
299
 
            CPLDebug("PG","Using column '%s' as FID for table '%s'", pszFIDColumn, pszTableIn );
 
331
            CPLDebug("PG","Using column '%s' as FID for table '%s'", pszFIDColumn, pszTableName );
300
332
            continue;
301
333
        }
302
334
        else if( EQUAL(pszType,"geometry") )
304
336
            bHasPostGISGeometry = TRUE;
305
337
            if (!pszGeomColumn)
306
338
                pszGeomColumn = CPLStrdup(oField.GetNameRef());
307
 
            poDefn->SetGeomType( wkbUnknown );
308
339
            continue;
309
340
        }
310
341
        else if( EQUAL(pszType,"geography") )
323
354
                if( EQUAL(pszType,"OID") )
324
355
                    bWkbAsOid = TRUE;
325
356
            }
326
 
            poDefn->SetGeomType( wkbUnknown );
327
357
            continue;
328
358
        }
329
359
 
438
468
 
439
469
    OGRPGClearResult( hResult );
440
470
 
441
 
    hResult = PQexec(hPGConn, "CLOSE mycursor");
442
 
    OGRPGClearResult( hResult );
443
 
 
444
 
    hResult = PQexec(hPGConn, "COMMIT");
445
 
    OGRPGClearResult( hResult );
446
 
 
 
471
    hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
 
472
    OGRPGClearResult( hResult );
 
473
 
 
474
    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
 
475
    OGRPGClearResult( hResult );
 
476
 
 
477
    /* If geometry type, SRID, etc... have always been set by SetGeometryInformation() */
 
478
    /* no need to issue a new SQL query. Just record the geom type in the layer definition */
 
479
    if (bGeometryInformationSet)
 
480
    {
 
481
        ;
 
482
    }
447
483
    // get layer geometry type (for PostGIS dataset)
448
 
    if ( bHasPostGISGeometry || bHasPostGISGeography )
 
484
    else if ( bHasPostGISGeometry || bHasPostGISGeography )
449
485
    {
450
486
      /* Get the geometry type and dimensions from the table, or */
451
487
      /* from its parents if it is a derived table, or from the parent of the parent, etc.. */
452
488
      int bGoOn = TRUE;
 
489
 
453
490
      while(bGoOn)
454
491
      {
455
492
        osCommand.Printf(
456
493
            "SELECT type, coord_dimension%s FROM %s WHERE f_table_name='%s'",
457
 
            (nSRSId == -2) ? ", srid" : "",
 
494
            (nSRSId == UNDETERMINED_SRID) ? ", srid" : "",
458
495
            (bHasPostGISGeometry) ? "geometry_columns" : "geography_columns",
459
 
            (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableIn);
 
496
            (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName);
460
497
        if (pszGeomColumn)
461
498
        {
462
499
            osCommand += CPLString().Printf(" AND %s='%s'",
468
505
            osCommand += CPLString().Printf(" AND f_table_schema='%s'", pszSchemaName);
469
506
        }
470
507
 
471
 
        hResult = PQexec(hPGConn,osCommand);
 
508
        hResult = OGRPG_PQexec(hPGConn,osCommand);
472
509
 
473
510
        if ( hResult && PQntuples(hResult) == 1 && !PQgetisnull(hResult,0,0) )
474
511
        {
475
512
            char * pszType = PQgetvalue(hResult,0,0);
476
 
            OGRwkbGeometryType nGeomType = wkbUnknown;
477
513
 
478
514
            nCoordDimension = MAX(2,MIN(3,atoi(PQgetvalue(hResult,0,1))));
479
515
 
480
 
            if (nSRSId == -2)
 
516
            if (nSRSId == UNDETERMINED_SRID)
481
517
                nSRSId = atoi(PQgetvalue(hResult,0,2));
482
518
 
483
 
            // check only standard OGC geometry types
484
 
            if ( EQUAL(pszType, "POINT") )
485
 
                nGeomType = wkbPoint;
486
 
            else if ( EQUAL(pszType,"LINESTRING"))
487
 
                nGeomType = wkbLineString;
488
 
            else if ( EQUAL(pszType,"POLYGON"))
489
 
                nGeomType = wkbPolygon;
490
 
            else if ( EQUAL(pszType,"MULTIPOINT"))
491
 
                nGeomType = wkbMultiPoint;
492
 
            else if ( EQUAL(pszType,"MULTILINESTRING"))
493
 
                nGeomType = wkbMultiLineString;
494
 
            else if ( EQUAL(pszType,"MULTIPOLYGON"))
495
 
                nGeomType = wkbMultiPolygon;
496
 
            else if ( EQUAL(pszType,"GEOMETRYCOLLECTION"))
497
 
                nGeomType = wkbGeometryCollection;
498
 
 
499
 
            if( nCoordDimension == 3 && nGeomType != wkbUnknown )
500
 
                nGeomType = (OGRwkbGeometryType) (nGeomType | wkb25DBit);
501
 
 
502
 
            CPLDebug("PG","Layer '%s' geometry type: %s:%s, Dim=%d",
503
 
                     pszTableIn, pszType, OGRGeometryTypeToName(nGeomType),
504
 
                     nCoordDimension );
505
 
 
506
 
            poDefn->SetGeomType( nGeomType );
 
519
            SetGeometryInformation(pszType, nCoordDimension, nSRSId,
 
520
                                   (bHasPostGISGeometry) ? GEOM_TYPE_GEOMETRY : GEOM_TYPE_GEOGRAPHY);
507
521
 
508
522
            bGoOn = FALSE;
509
523
        }
510
524
        else
511
525
        {
 
526
            CPLString osEscapedTableNameSingleQuote = OGRPGEscapeString(hPGConn,
 
527
                    (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName, -1, "");
 
528
            const char* pszEscapedTableNameSingleQuote = osEscapedTableNameSingleQuote.c_str();
 
529
 
512
530
            /* Fetch the name of the parent table */
513
531
            if (pszSchemaName)
514
532
            {
515
533
                osCommand.Printf("SELECT pg_class.relname FROM pg_class WHERE oid = "
516
534
                                "(SELECT pg_inherits.inhparent FROM pg_inherits WHERE inhrelid = "
517
 
                                "(SELECT c.oid FROM pg_class c, pg_namespace n WHERE c.relname = '%s' AND c.relnamespace=n.oid AND n.nspname = '%s'))",
518
 
                                (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableIn, pszSchemaName );
 
535
                                "(SELECT c.oid FROM pg_class c, pg_namespace n WHERE c.relname = %s AND c.relnamespace=n.oid AND n.nspname = '%s'))",
 
536
                                pszEscapedTableNameSingleQuote, pszSchemaName );
519
537
            }
520
538
            else
521
539
            {
522
540
                osCommand.Printf("SELECT pg_class.relname FROM pg_class WHERE oid = "
523
541
                                "(SELECT pg_inherits.inhparent FROM pg_inherits WHERE inhrelid = "
524
 
                                "(SELECT pg_class.oid FROM pg_class WHERE relname = '%s'))",
525
 
                                (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableIn );
 
542
                                "(SELECT pg_class.oid FROM pg_class WHERE relname = %s))",
 
543
                                pszEscapedTableNameSingleQuote );
526
544
            }
527
545
 
528
546
            OGRPGClearResult( hResult );
529
 
            hResult = PQexec(hPGConn, osCommand.c_str() );
 
547
            hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
530
548
 
531
549
            if ( hResult && PQntuples( hResult ) == 1 && !PQgetisnull( hResult,0,0 ) )
532
550
            {
542
560
 
543
561
        OGRPGClearResult( hResult );
544
562
      }
545
 
    }
 
563
 
 
564
      if (nSRSId == UNDETERMINED_SRID)
 
565
          nSRSId = poDS->GetUndefinedSRID();
 
566
    }
 
567
    else if (pszGeomColumn == NULL)
 
568
    {
 
569
        nGeomType = wkbNone;
 
570
    }
 
571
 
 
572
    poDefn->SetGeomType( nGeomType );
546
573
 
547
574
    return poDefn;
548
575
}
554
581
void OGRPGTableLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
555
582
 
556
583
{
 
584
    GetLayerDefn();
 
585
 
557
586
    if( InstallFilter( poGeomIn ) )
558
587
    {
559
588
        BuildWhere();
576
605
 
577
606
    if( m_poFilterGeom != NULL && (bHasPostGISGeometry || bHasPostGISGeography) )
578
607
    {
 
608
        char szBox3D_1[128];
 
609
        char szBox3D_2[128];
 
610
        char* pszComma;
579
611
        OGREnvelope  sEnvelope;
580
612
 
581
613
        m_poFilterGeom->getEnvelope( &sEnvelope );
582
 
        osWHERE.Printf("WHERE \"%s\" && SetSRID('BOX3D(%.12f %.12f, %.12f %.12f)'::box3d,%d) ",
583
 
                       pszGeomColumn,
584
 
                       sEnvelope.MinX, sEnvelope.MinY,
585
 
                       sEnvelope.MaxX, sEnvelope.MaxY,
586
 
                       nSRSId );
 
614
        snprintf(szBox3D_1, sizeof(szBox3D_1), "%.12f %.12f", sEnvelope.MinX, sEnvelope.MinY);
 
615
        while((pszComma = strchr(szBox3D_1, ',')) != NULL)
 
616
            *pszComma = '.';
 
617
        snprintf(szBox3D_2, sizeof(szBox3D_2), "%.12f %.12f", sEnvelope.MaxX, sEnvelope.MaxY);
 
618
        while((pszComma = strchr(szBox3D_2, ',')) != NULL)
 
619
            *pszComma = '.';
 
620
        osWHERE.Printf("WHERE %s && %s('BOX3D(%s, %s)'::box3d,%d) ",
 
621
                       OGRPGEscapeColumnName(pszGeomColumn).c_str(),
 
622
                       (poDS->sPostGISVersion.nMajor >= 2) ? "ST_SetSRID" : "SetSRID",
 
623
                       szBox3D_1, szBox3D_2, nSRSId );
587
624
    }
588
625
 
589
626
    if( strlen(osQuery) > 0 )
630
667
void OGRPGTableLayer::ResetReading()
631
668
 
632
669
{
 
670
    GetLayerDefn();
 
671
 
633
672
    bUseCopy = USE_COPY_UNSET;
634
673
 
635
674
    BuildFullQueryStatement();
644
683
OGRFeature *OGRPGTableLayer::GetNextFeature()
645
684
 
646
685
{
 
686
    GetLayerDefn();
 
687
 
647
688
    for( ; TRUE; )
648
689
    {
649
690
        OGRFeature      *poFeature;
681
722
 
682
723
    if( bHasFid && poFeatureDefn->GetFieldIndex( pszFIDColumn ) == -1 )
683
724
    {
684
 
        osFieldList += "\"";
685
 
        osFieldList += pszFIDColumn;
686
 
        osFieldList += "\"";
 
725
        osFieldList += OGRPGEscapeColumnName(pszFIDColumn);
687
726
    }
688
727
 
689
728
    if( pszGeomColumn )
695
734
        {
696
735
            if ( poDS->bUseBinaryCursor )
697
736
            {
698
 
                osFieldList += "AsEWKB(\"";
699
 
                osFieldList += pszGeomColumn;
700
 
                osFieldList += "\")";
 
737
                osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
 
738
            }
 
739
            else if (CSLTestBoolean(CPLGetConfigOption("PG_USE_BASE64", "NO")) &&
 
740
                     nCoordDimension != 4 /* we don't know how to decode 4-dim EWKB for now */)
 
741
            {
 
742
                if (poDS->sPostGISVersion.nMajor >= 2)
 
743
                    osFieldList += "encode(ST_AsEWKB(";
 
744
                else
 
745
                    osFieldList += "encode(AsEWKB(";
 
746
                osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
 
747
                osFieldList += "), 'base64') AS EWKBBase64";
 
748
            }
 
749
            else if ( !CSLTestBoolean(CPLGetConfigOption("PG_USE_TEXT", "NO")) &&
 
750
                     nCoordDimension != 4 && /* we don't know how to decode 4-dim EWKB for now */
 
751
                      /* perhaps works also for older version, but I didn't check */
 
752
                      (poDS->sPostGISVersion.nMajor > 1 ||
 
753
                      (poDS->sPostGISVersion.nMajor == 1 && poDS->sPostGISVersion.nMinor >= 1)) )
 
754
            {
 
755
                /* This will return EWKB in an hex encoded form */
 
756
                osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
701
757
            }
702
758
            else if ( poDS->sPostGISVersion.nMajor >= 1 )
703
759
            {
704
 
                osFieldList += "AsEWKT(\"";
705
 
                osFieldList += pszGeomColumn;
706
 
                osFieldList += "\")";
 
760
                if (poDS->sPostGISVersion.nMajor >= 2)
 
761
                    osFieldList += "ST_AsEWKT(";
 
762
                else
 
763
                    osFieldList += "AsEWKT(";
 
764
                osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
 
765
                osFieldList += ")";
707
766
            }
708
767
            else
709
768
            {
710
 
                osFieldList += "AsText(\"";
711
 
                osFieldList += pszGeomColumn;
712
 
                osFieldList += "\")";
 
769
                osFieldList += "AsText(";
 
770
                osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
 
771
                osFieldList += ")";
713
772
            }
714
773
        }
715
774
        else if ( bHasPostGISGeography )
716
775
        {
717
776
            if ( poDS->bUseBinaryCursor )
718
777
            {
719
 
                osFieldList += "ST_AsBinary(\"";
720
 
                osFieldList += pszGeomColumn;
721
 
                osFieldList += "\")";
 
778
                osFieldList += "ST_AsBinary(";
 
779
                osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
 
780
                osFieldList += ")";
 
781
            }
 
782
            else if (CSLTestBoolean(CPLGetConfigOption("PG_USE_BASE64", "NO")))
 
783
            {
 
784
                osFieldList += "encode(ST_AsBinary(";
 
785
                osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
 
786
                osFieldList += "), 'base64') AS BinaryBase64";
 
787
            }
 
788
            else if ( !CSLTestBoolean(CPLGetConfigOption("PG_USE_TEXT", "NO")) )
 
789
            {
 
790
                osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
722
791
            }
723
792
            else
724
793
            {
725
 
                osFieldList += "ST_AsText(\"";
726
 
                osFieldList += pszGeomColumn;
727
 
                osFieldList += "\")";
 
794
                osFieldList += "ST_AsText(";
 
795
                osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
 
796
                osFieldList += ")";
728
797
            }
729
798
        }
730
799
        else
731
800
        {
732
 
            osFieldList += "\"";
733
 
            osFieldList += pszGeomColumn;
734
 
            osFieldList += "\"";
 
801
            osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
735
802
        }
736
803
    }
737
804
 
747
814
        if ( poDS->bUseBinaryCursor &&
748
815
             poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDateTime)
749
816
        {
750
 
            osFieldList += "CAST (\"";
751
 
            osFieldList += pszName ;
752
 
            osFieldList += "\" AS text)";
 
817
            osFieldList += "CAST (";
 
818
            osFieldList += OGRPGEscapeColumnName(pszName);
 
819
            osFieldList += " AS text)";
753
820
        }
754
821
        else
755
822
        {
756
 
            osFieldList += "\"";
757
 
            osFieldList += pszName;
758
 
            osFieldList += "\"" ;
 
823
            osFieldList += OGRPGEscapeColumnName(pszName);
759
824
        }
760
825
    }
761
826
 
769
834
OGRErr OGRPGTableLayer::SetAttributeFilter( const char *pszQuery )
770
835
 
771
836
{
 
837
    GetLayerDefn();
 
838
 
772
839
    if( pszQuery == NULL )
773
840
        osQuery = "";
774
841
    else
792
859
    PGresult    *hResult = NULL;
793
860
    CPLString   osCommand;
794
861
 
 
862
    GetLayerDefn();
 
863
 
795
864
/* -------------------------------------------------------------------- */
796
865
/*      We can only delete features if we have a well defined FID       */
797
866
/*      column to target.                                               */
809
878
/* -------------------------------------------------------------------- */
810
879
/*      Form the statement to drop the record.                          */
811
880
/* -------------------------------------------------------------------- */
812
 
    osCommand.Printf( "DELETE FROM %s WHERE \"%s\" = %ld",
813
 
                      pszSqlTableName, pszFIDColumn, nFID );
 
881
    osCommand.Printf( "DELETE FROM %s WHERE %s = %ld",
 
882
                      pszSqlTableName, OGRPGEscapeColumnName(pszFIDColumn).c_str(), nFID );
814
883
 
815
884
/* -------------------------------------------------------------------- */
816
885
/*      Execute the delete.                                             */
821
890
    if( eErr != OGRERR_NONE )
822
891
        return eErr;
823
892
 
824
 
    hResult = PQexec(hPGConn, osCommand);
 
893
    hResult = OGRPG_PQexec(hPGConn, osCommand);
825
894
 
826
895
    if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
827
896
    {
896
965
                strcat( pszNeedToFree+nOff, "," );
897
966
 
898
967
            nOff += strlen(pszNeedToFree+nOff);
899
 
            sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
900
968
            //Check for special values. They need to be quoted.
901
 
            if( strcmp( pszNeedToFree+nOff, "nan" ) == 0 )
 
969
            if( CPLIsNan(padfItems[j]) )
902
970
                sprintf( pszNeedToFree+nOff, "NaN" );
903
 
            else if( strcmp( pszNeedToFree+nOff, "inf" ) == 0 )
904
 
                sprintf( pszNeedToFree+nOff, "Infinity" );
905
 
            else if( strcmp( pszNeedToFree+nOff, "-inf" ) == 0 )
906
 
                sprintf( pszNeedToFree+nOff, "-Infinity" );
 
971
            else if( CPLIsInf(padfItems[j]) )
 
972
                sprintf( pszNeedToFree+nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
 
973
            else
 
974
                sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
 
975
 
 
976
            char* pszComma = strchr(pszNeedToFree+nOff, ',');
 
977
            if (pszComma)
 
978
                *pszComma = '.';
907
979
        }
908
980
        strcat( pszNeedToFree+nOff, "}'" );
909
981
 
926
998
    // Binary formatting
927
999
    else if( nOGRFieldType == OFTBinary )
928
1000
    {
 
1001
        if (poDS->bUseEscapeStringSyntax)
 
1002
            osCommand += "E";
 
1003
 
929
1004
        osCommand += "'";
930
1005
 
931
1006
        int nLen = 0;
957
1032
    }
958
1033
    else if ( nOGRFieldType == OFTReal )
959
1034
    {
 
1035
        char* pszComma = strchr((char*)pszStrValue, ',');
 
1036
        if (pszComma)
 
1037
            *pszComma = '.';
960
1038
        //Check for special values. They need to be quoted.
961
 
        if( strcmp( pszStrValue, "nan" ) == 0 )
 
1039
        double dfVal = poFeature->GetFieldAsDouble(i);
 
1040
        if( CPLIsNan(dfVal) )
962
1041
            pszStrValue = "'NaN'";
963
 
        else if( strcmp( pszStrValue, "inf" ) == 0 )
964
 
            pszStrValue = "'Infinity'";
965
 
        else if( strcmp( pszStrValue, "-inf" ) == 0 )
966
 
            pszStrValue = "'-Infinity'";
 
1042
        else if( CPLIsInf(dfVal) )
 
1043
            pszStrValue = (dfVal > 0) ? "'Infinity'" : "'-Infinity'";
967
1044
    }
968
1045
 
969
1046
    if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTReal
995
1072
    int                 bNeedComma = FALSE;
996
1073
    OGRErr              eErr = OGRERR_FAILURE;
997
1074
 
 
1075
    GetLayerDefn();
 
1076
 
998
1077
    if( NULL == poFeature )
999
1078
    {
1000
1079
        CPLError( CE_Failure, CPLE_AppDefined,
1041
1120
 
1042
1121
                if( pszBytea != NULL )
1043
1122
                {
 
1123
                    if (poDS->bUseEscapeStringSyntax)
 
1124
                        osCommand += "E";
1044
1125
                    osCommand = osCommand + "'" + pszBytea + "'";
1045
1126
                    CPLFree( pszBytea );
1046
1127
                }
1065
1146
    }
1066
1147
    else if( bHasPostGISGeometry || bHasPostGISGeography )
1067
1148
    {
1068
 
        osCommand = osCommand + "\"" + pszGeomColumn + "\" = ";
1069
 
        char    *pszWKT = NULL;
1070
 
 
 
1149
        osCommand = osCommand + OGRPGEscapeColumnName(pszGeomColumn) + " = ";
 
1150
        OGRGeometry *poGeom = NULL;
 
1151
        
1071
1152
        if( poFeature->GetGeometryRef() != NULL )
1072
1153
        {
1073
 
            OGRGeometry *poGeom = (OGRGeometry *) poFeature->GetGeometryRef();
 
1154
            poGeom = (OGRGeometry *) poFeature->GetGeometryRef();
1074
1155
 
1075
1156
            poGeom->closeRings();
1076
1157
            poGeom->setCoordinateDimension( nCoordDimension );
1077
1158
 
1078
 
            poGeom->exportToWkt( &pszWKT );
1079
1159
        }
1080
1160
 
1081
 
        if( pszWKT != NULL )
 
1161
        if ( !CSLTestBoolean(CPLGetConfigOption("PG_USE_TEXT", "NO")) )
1082
1162
        {
1083
 
            if( bHasPostGISGeography )
1084
 
                osCommand +=
1085
 
                    CPLString().Printf(
1086
 
                        "ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1087
 
            else if( poDS->sPostGISVersion.nMajor >= 1 )
1088
 
                osCommand +=
1089
 
                    CPLString().Printf(
1090
 
                        "GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
 
1163
            if ( poGeom != NULL )
 
1164
            {
 
1165
                char* pszHexEWKB = GeometryToHex( poGeom, nSRSId );
 
1166
                if ( bHasPostGISGeography )
 
1167
                    osCommand += CPLString().Printf("'%s'::GEOGRAPHY", pszHexEWKB);
 
1168
                else
 
1169
                    osCommand += CPLString().Printf("'%s'::GEOMETRY", pszHexEWKB);
 
1170
                OGRFree( pszHexEWKB );
 
1171
            }
1091
1172
            else
1092
 
                osCommand += 
1093
 
                    CPLString().Printf(
1094
 
                        "GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
1095
 
            OGRFree( pszWKT );
 
1173
                osCommand += "NULL";    
1096
1174
        }
1097
1175
        else
1098
 
            osCommand += "NULL";
1099
 
 
 
1176
        {
 
1177
            char    *pszWKT = NULL;
 
1178
    
 
1179
            if (poGeom != NULL)
 
1180
                poGeom->exportToWkt( &pszWKT );
 
1181
 
 
1182
            if( pszWKT != NULL )
 
1183
            {
 
1184
                if( bHasPostGISGeography )
 
1185
                    osCommand +=
 
1186
                        CPLString().Printf(
 
1187
                            "ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
 
1188
                else if( poDS->sPostGISVersion.nMajor >= 1 )
 
1189
                    osCommand +=
 
1190
                        CPLString().Printf(
 
1191
                            "GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
 
1192
                else
 
1193
                    osCommand += 
 
1194
                        CPLString().Printf(
 
1195
                            "GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
 
1196
                OGRFree( pszWKT );
 
1197
            }
 
1198
            else
 
1199
                osCommand += "NULL";
 
1200
 
 
1201
        }
1100
1202
        bNeedComma = TRUE;
1101
1203
    }
1102
1204
 
1108
1210
            bNeedComma = TRUE;
1109
1211
 
1110
1212
        osCommand = osCommand 
1111
 
            + "\"" + poFeatureDefn->GetFieldDefn(i)->GetNameRef() + "\" = ";
 
1213
            + OGRPGEscapeColumnName(poFeatureDefn->GetFieldDefn(i)->GetNameRef()) + " = ";
1112
1214
 
1113
1215
        if( !poFeature->IsFieldSet( i ) )
1114
1216
        {
1122
1224
 
1123
1225
    /* Add the WHERE clause */
1124
1226
    osCommand += " WHERE ";
1125
 
    osCommand = osCommand + "\"" + pszFIDColumn + "\" = ";
 
1227
    osCommand = osCommand + OGRPGEscapeColumnName(pszFIDColumn) + " = ";
1126
1228
    osCommand += CPLString().Printf( "%ld ", poFeature->GetFID() );
1127
1229
 
1128
1230
/* -------------------------------------------------------------------- */
1129
1231
/*      Execute the update.                                             */
1130
1232
/* -------------------------------------------------------------------- */
1131
 
    hResult = PQexec(hPGConn, osCommand);
 
1233
    hResult = OGRPG_PQexec(hPGConn, osCommand);
1132
1234
    if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
1133
1235
    {
1134
1236
        CPLError( CE_Failure, CPLE_AppDefined,
1152
1254
/************************************************************************/
1153
1255
 
1154
1256
OGRErr OGRPGTableLayer::CreateFeature( OGRFeature *poFeature )
1155
 
 
1257
{
 
1258
    GetLayerDefn();
 
1259
 
1156
1260
    if( NULL == poFeature )
1157
1261
    {
1158
1262
        CPLError( CE_Failure, CPLE_AppDefined,
1178
1282
}
1179
1283
 
1180
1284
/************************************************************************/
 
1285
/*                       OGRPGEscapeColumnName( )                       */
 
1286
/************************************************************************/
 
1287
 
 
1288
CPLString OGRPGEscapeColumnName(const char* pszColumnName)
 
1289
{
 
1290
    CPLString osStr;
 
1291
 
 
1292
    osStr += "\"";
 
1293
 
 
1294
    char ch;
 
1295
    for(int i=0; (ch = pszColumnName[i]) != '\0'; i++)
 
1296
    {
 
1297
        if (ch == '"')
 
1298
            osStr.append(1, ch);
 
1299
        osStr.append(1, ch);
 
1300
    }
 
1301
 
 
1302
    osStr += "\"";
 
1303
 
 
1304
    return osStr;
 
1305
}
 
1306
 
 
1307
/************************************************************************/
1181
1308
/*                         OGRPGEscapeString( )                         */
1182
1309
/************************************************************************/
1183
1310
 
1311
1438
        return eErr;
1312
1439
    }
1313
1440
 
 
1441
    int bEmptyInsert = FALSE;
 
1442
 
1314
1443
/* -------------------------------------------------------------------- */
1315
1444
/*      Form the INSERT command.                                        */
1316
1445
/* -------------------------------------------------------------------- */
1325
1454
    }
1326
1455
    else if( (bHasPostGISGeometry || bHasPostGISGeography) && poGeom != NULL )
1327
1456
    {
1328
 
        osCommand = osCommand + "\"" + pszGeomColumn + "\" ";
 
1457
        osCommand = osCommand + OGRPGEscapeColumnName(pszGeomColumn) + " ";
1329
1458
        bNeedComma = TRUE;
1330
1459
    }
1331
1460
 
 
1461
    /* Use case of ogr_pg_60 test */
1332
1462
    if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != NULL )
1333
1463
    {
1334
1464
        if( bNeedComma )
1335
1465
            osCommand += ", ";
1336
1466
        
1337
 
        osCommand = osCommand + "\"" + pszFIDColumn + "\" ";
 
1467
        osCommand = osCommand + OGRPGEscapeColumnName(pszFIDColumn) + " ";
1338
1468
        bNeedComma = TRUE;
1339
1469
    }
1340
1470
 
1350
1480
            osCommand += ", ";
1351
1481
 
1352
1482
        osCommand = osCommand 
1353
 
            + "\"" + poFeatureDefn->GetFieldDefn(i)->GetNameRef() + "\"";
 
1483
            + OGRPGEscapeColumnName(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
1354
1484
    }
1355
1485
 
 
1486
    if (!bNeedComma)
 
1487
        bEmptyInsert = TRUE;
 
1488
 
1356
1489
    osCommand += ") VALUES (";
1357
1490
 
1358
1491
    /* Set the geometry */
1359
 
    bNeedComma = poGeom != NULL;
 
1492
    bNeedComma = FALSE;
1360
1493
    if( (bHasPostGISGeometry || bHasPostGISGeography) && poGeom != NULL)
1361
1494
    {
1362
 
        char    *pszWKT = NULL;
1363
1495
        
1364
1496
        CheckGeomTypeCompatibility(poGeom);
1365
1497
 
1366
1498
        poGeom->closeRings();
1367
1499
        poGeom->setCoordinateDimension( nCoordDimension );
1368
1500
 
1369
 
        poGeom->exportToWkt( &pszWKT );
1370
1501
 
1371
 
        if( pszWKT != NULL )
 
1502
        if ( !CSLTestBoolean(CPLGetConfigOption("PG_USE_TEXT", "NO")) )
1372
1503
        {
1373
 
            if( bHasPostGISGeography )
1374
 
                osCommand +=
1375
 
                    CPLString().Printf(
1376
 
                        "ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1377
 
            else if( poDS->sPostGISVersion.nMajor >= 1 )
1378
 
                osCommand +=
1379
 
                    CPLString().Printf(
1380
 
                        "GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
 
1504
            char    *pszHexEWKB = GeometryToHex( poGeom, nSRSId );
 
1505
            if ( bHasPostGISGeography )
 
1506
                osCommand += CPLString().Printf("'%s'::GEOGRAPHY", pszHexEWKB);
1381
1507
            else
1382
 
                osCommand += 
1383
 
                    CPLString().Printf(
1384
 
                        "GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
1385
 
            OGRFree( pszWKT );
 
1508
                osCommand += CPLString().Printf("'%s'::GEOMETRY", pszHexEWKB);
 
1509
            OGRFree( pszHexEWKB );
1386
1510
        }
1387
1511
        else
1388
 
            osCommand += "''";
 
1512
        { 
 
1513
            char    *pszWKT = NULL;
 
1514
            poGeom->exportToWkt( &pszWKT );
 
1515
 
 
1516
            if( pszWKT != NULL )
 
1517
            {
 
1518
                if( bHasPostGISGeography )
 
1519
                    osCommand +=
 
1520
                        CPLString().Printf(
 
1521
                            "ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
 
1522
                else if( poDS->sPostGISVersion.nMajor >= 1 )
 
1523
                    osCommand +=
 
1524
                        CPLString().Printf(
 
1525
                            "GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
 
1526
                else
 
1527
                    osCommand += 
 
1528
                        CPLString().Printf(
 
1529
                            "GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
 
1530
                OGRFree( pszWKT );
 
1531
            }
 
1532
            else
 
1533
                osCommand += "''";
 
1534
            
 
1535
        }
 
1536
        bNeedComma = TRUE;
1389
1537
    }
1390
1538
    else if( bHasWkb && !bWkbAsOid && poGeom != NULL )
1391
1539
    {
1393
1541
 
1394
1542
        if( pszBytea != NULL )
1395
1543
        {
 
1544
            if (poDS->bUseEscapeStringSyntax)
 
1545
                osCommand += "E";
1396
1546
            osCommand = osCommand + "'" + pszBytea + "'";
1397
1547
            CPLFree( pszBytea );
1398
1548
        }
1399
1549
        else
1400
1550
            osCommand += "''";
 
1551
            
 
1552
        bNeedComma = TRUE;
1401
1553
    }
1402
1554
    else if( bHasWkb && bWkbAsOid && poGeom != NULL )
1403
1555
    {
1409
1561
        }
1410
1562
        else
1411
1563
            osCommand += "''";
 
1564
            
 
1565
        bNeedComma = TRUE;
1412
1566
    }
1413
1567
 
1414
 
    /* Set the FID */
1415
1568
    if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != NULL )
1416
1569
    {
1417
1570
        if( bNeedComma )
1436
1589
 
1437
1590
    osCommand += ")";
1438
1591
 
 
1592
    if (bEmptyInsert)
 
1593
        osCommand.Printf( "INSERT INTO %s DEFAULT VALUES", pszSqlTableName );
 
1594
 
 
1595
    int bReturnRequested = FALSE;
 
1596
    /* RETURNING is only available since Postgres 8.2 */
 
1597
    /* We only get the FID, but we also could add the unset fields to get */
 
1598
    /* the default values */
 
1599
    if (bRetrieveFID && pszFIDColumn != NULL && poFeature->GetFID() == OGRNullFID &&
 
1600
        (poDS->sPostgreSQLVersion.nMajor >= 9 ||
 
1601
         (poDS->sPostgreSQLVersion.nMajor == 8 && poDS->sPostgreSQLVersion.nMinor >= 2)))
 
1602
    {
 
1603
        bReturnRequested = TRUE;
 
1604
        osCommand += " RETURNING ";
 
1605
        osCommand += OGRPGEscapeColumnName(pszFIDColumn);
 
1606
    }
 
1607
 
1439
1608
/* -------------------------------------------------------------------- */
1440
1609
/*      Execute the insert.                                             */
1441
1610
/* -------------------------------------------------------------------- */
1442
 
    hResult = PQexec(hPGConn, osCommand);
1443
 
    if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
 
1611
    hResult = OGRPG_PQexec(hPGConn, osCommand);
 
1612
    if (bReturnRequested && PQresultStatus(hResult) == PGRES_TUPLES_OK &&
 
1613
        PQntuples(hResult) == 1 && PQnfields(hResult) == 1 )
 
1614
    {
 
1615
        const char* pszFID = PQgetvalue(hResult, 0, 0 );
 
1616
        long nFID = atol(pszFID);
 
1617
        poFeature->SetFID(nFID);
 
1618
    }
 
1619
    else if( bReturnRequested || PQresultStatus(hResult) != PGRES_COMMAND_OK )
1444
1620
    {
1445
1621
        CPLError( CE_Failure, CPLE_AppDefined,
1446
1622
                  "INSERT command for new feature failed.\n%s\nCommand: %s",
1447
1623
                  PQerrorMessage(hPGConn), osCommand.c_str() );
1448
1624
 
 
1625
        if( !bHasWarnedAlreadySetFID && poFeature->GetFID() != OGRNullFID &&
 
1626
            pszFIDColumn != NULL )
 
1627
        {
 
1628
            bHasWarnedAlreadySetFID = TRUE;
 
1629
            CPLError(CE_Warning, CPLE_AppDefined,
 
1630
                    "You've inserted feature with an already set FID and that's perhaps the reason for the failure. "
 
1631
                    "If so, this can happen if you reuse the same feature object for sequential insertions. "
 
1632
                    "Indeed, since GDAL 1.8.0, the FID of an inserted feature is got from the server, so it is not a good idea"
 
1633
                    "to reuse it afterwards... All in all, try unsetting the FID with SetFID(-1) before calling CreateFeature()");
 
1634
        }
 
1635
 
1449
1636
        OGRPGClearResult( hResult );
1450
1637
 
1451
1638
        poDS->SoftRollback();
1453
1640
        return OGRERR_FAILURE;
1454
1641
    }
1455
1642
 
1456
 
#ifdef notdef
1457
 
    /* Should we use this oid to get back the FID and assign back to the
1458
 
       feature?  I think we are supposed to. */
1459
 
    Oid nNewOID = PQoidValue( hResult );
1460
 
    printf( "nNewOID = %d\n", (int) nNewOID );
1461
 
#endif
1462
 
 
1463
1643
    OGRPGClearResult( hResult );
1464
1644
 
1465
1645
    return poDS->SoftCommit();
1496
1676
        osCommand += pszGeom,
1497
1677
        CPLFree( pszGeom );
1498
1678
    }
1499
 
    else
 
1679
    else if (nGeomType != wkbNone)
1500
1680
    {
1501
1681
        osCommand = "\\N";
1502
1682
    }
1527
1707
        const char *pszStrValue = poFeature->GetFieldAsString(i);
1528
1708
        char *pszNeedToFree = NULL;
1529
1709
 
1530
 
        if (osCommand.size() > 0)
 
1710
        if (i > 0 || osCommand.size() > 0)
1531
1711
            osCommand += "\t";
1532
1712
            
1533
1713
        if( !poFeature->IsFieldSet( i ) )
1573
1753
                    strcat( pszNeedToFree+nOff, "," );
1574
1754
 
1575
1755
                nOff += strlen(pszNeedToFree+nOff);
1576
 
                sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
1577
1756
                //Check for special values. They need to be quoted.
1578
 
                if( strcmp( pszNeedToFree+nOff, "nan" ) == 0 )
1579
 
                    sprintf( pszNeedToFree+nOff, "'NaN'" );
1580
 
                else if( strcmp( pszNeedToFree+nOff, "inf" ) == 0 )
1581
 
                    sprintf( pszNeedToFree+nOff, "'Infinity'" );
1582
 
                else if( strcmp( pszNeedToFree+nOff, "-inf" ) == 0 )
1583
 
                    sprintf( pszNeedToFree+nOff, "'-Infinity'" );
 
1757
                if( CPLIsNan(padfItems[j]) )
 
1758
                    sprintf( pszNeedToFree+nOff, "NaN" );
 
1759
                else if( CPLIsInf(padfItems[j]) )
 
1760
                    sprintf( pszNeedToFree+nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
 
1761
                else
 
1762
                    sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
 
1763
 
 
1764
                char* pszComma = strchr(pszNeedToFree+nOff, ',');
 
1765
                if (pszComma)
 
1766
                    *pszComma = '.';
1584
1767
            }
1585
1768
            strcat( pszNeedToFree+nOff, "}" );
1586
1769
            pszStrValue = pszNeedToFree;
1608
1791
 
1609
1792
        else if( nOGRFieldType == OFTReal )
1610
1793
        {
 
1794
            char* pszComma = strchr((char*)pszStrValue, ',');
 
1795
            if (pszComma)
 
1796
                *pszComma = '.';
1611
1797
            //Check for special values. They need to be quoted.
1612
 
            if( strcmp( pszStrValue, "nan" ) == 0 )
1613
 
                pszStrValue = "'NaN'";
1614
 
            else if( strcmp( pszStrValue, "inf" ) == 0 )
1615
 
                pszStrValue = "'Infinity'";
1616
 
            else if( strcmp( pszStrValue, "-inf" ) == 0 )
1617
 
                pszStrValue = "'-Infinity'";
 
1798
            double dfVal = poFeature->GetFieldAsDouble(i);
 
1799
            if( CPLIsNan(dfVal) )
 
1800
                pszStrValue = "NaN";
 
1801
            else if( CPLIsInf(dfVal) )
 
1802
                pszStrValue = (dfVal > 0) ? "Infinity" : "-Infinity";
1618
1803
        }
1619
1804
 
1620
1805
        if( nOGRFieldType != OFTIntegerList &&
1705
1890
int OGRPGTableLayer::TestCapability( const char * pszCap )
1706
1891
 
1707
1892
{
 
1893
    GetLayerDefn();
 
1894
 
1708
1895
    if ( bUpdateAccess )
1709
1896
    {
1710
 
        if( EQUAL(pszCap,OLCSequentialWrite) || EQUAL(pszCap,OLCCreateField) )
 
1897
        if( EQUAL(pszCap,OLCSequentialWrite) ||
 
1898
            EQUAL(pszCap,OLCCreateField) ||
 
1899
            EQUAL(pszCap,OLCDeleteField) ||
 
1900
            EQUAL(pszCap,OLCAlterFieldDefn) )
1711
1901
            return TRUE;
1712
1902
 
1713
 
        else if( EQUAL(pszCap,OLCRandomWrite) )
 
1903
        else if( EQUAL(pszCap,OLCRandomWrite) ||
 
1904
                 EQUAL(pszCap,OLCDeleteFeature) )
1714
1905
            return bHasFid;
1715
1906
    }
1716
1907
 
1738
1929
}
1739
1930
 
1740
1931
/************************************************************************/
1741
 
/*                            CreateField()                             */
 
1932
/*                        OGRPGTableLayerGetType()                      */
1742
1933
/************************************************************************/
1743
1934
 
1744
 
OGRErr OGRPGTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
1745
 
 
 
1935
static CPLString OGRPGTableLayerGetType(OGRFieldDefn& oField,
 
1936
                                        int bPreservePrecision,
 
1937
                                        int bApproxOK)
1746
1938
{
1747
 
    PGconn              *hPGConn = poDS->GetPGConn();
1748
 
    PGresult            *hResult = NULL;
1749
 
    CPLString           osCommand;
1750
1939
    char                szFieldType[256];
1751
 
    OGRFieldDefn        oField( poFieldIn );
1752
 
 
1753
 
/* -------------------------------------------------------------------- */
1754
 
/*      Do we want to "launder" the column names into Postgres          */
1755
 
/*      friendly format?                                                */
1756
 
/* -------------------------------------------------------------------- */
1757
 
    if( bLaunderColumnNames )
1758
 
    {
1759
 
        char    *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
1760
 
 
1761
 
        oField.SetName( pszSafeName );
1762
 
        CPLFree( pszSafeName );
1763
 
 
1764
 
        if( EQUAL(oField.GetNameRef(),"oid") )
1765
 
        {
1766
 
            CPLError( CE_Warning, CPLE_AppDefined,
1767
 
                      "Renaming field 'oid' to 'oid_' to avoid conflict with internal oid field." );
1768
 
            oField.SetName( "oid_" );
1769
 
        }
1770
 
    }
1771
1940
 
1772
1941
/* -------------------------------------------------------------------- */
1773
1942
/*      Work out the PostgreSQL type.                                   */
1790
1959
    }
1791
1960
    else if( oField.GetType() == OFTString )
1792
1961
    {
1793
 
        if( oField.GetWidth() == 0 || !bPreservePrecision )
1794
 
            strcpy( szFieldType, "VARCHAR" );
 
1962
        if (oField.GetWidth() > 0 &&  bPreservePrecision )
 
1963
            sprintf( szFieldType, "VARCHAR(%d)",  oField.GetWidth() );
1795
1964
        else
1796
 
            sprintf( szFieldType, "CHAR(%d)", oField.GetWidth() );
 
1965
            strcpy( szFieldType, "VARCHAR");
1797
1966
    }
1798
1967
    else if( oField.GetType() == OFTIntegerList )
1799
1968
    {
1837
2006
                  "Can't create field %s with type %s on PostgreSQL layers.",
1838
2007
                  oField.GetNameRef(),
1839
2008
                  OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
1840
 
 
 
2009
        strcpy( szFieldType, "");
 
2010
    }
 
2011
 
 
2012
    return szFieldType;
 
2013
}
 
2014
 
 
2015
/************************************************************************/
 
2016
/*                            CreateField()                             */
 
2017
/************************************************************************/
 
2018
 
 
2019
OGRErr OGRPGTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
 
2020
 
 
2021
{
 
2022
    PGconn              *hPGConn = poDS->GetPGConn();
 
2023
    PGresult            *hResult = NULL;
 
2024
    CPLString           osCommand;
 
2025
    CPLString           osFieldType;
 
2026
    OGRFieldDefn        oField( poFieldIn );
 
2027
 
 
2028
    GetLayerDefn();
 
2029
 
 
2030
/* -------------------------------------------------------------------- */
 
2031
/*      Do we want to "launder" the column names into Postgres          */
 
2032
/*      friendly format?                                                */
 
2033
/* -------------------------------------------------------------------- */
 
2034
    if( bLaunderColumnNames )
 
2035
    {
 
2036
        char    *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
 
2037
 
 
2038
        oField.SetName( pszSafeName );
 
2039
        CPLFree( pszSafeName );
 
2040
 
 
2041
        if( EQUAL(oField.GetNameRef(),"oid") )
 
2042
        {
 
2043
            CPLError( CE_Warning, CPLE_AppDefined,
 
2044
                      "Renaming field 'oid' to 'oid_' to avoid conflict with internal oid field." );
 
2045
            oField.SetName( "oid_" );
 
2046
        }
 
2047
    }
 
2048
 
 
2049
    osFieldType = OGRPGTableLayerGetType(oField, bPreservePrecision, bApproxOK);
 
2050
    if (osFieldType.size() == 0)
1841
2051
        return OGRERR_FAILURE;
1842
 
    }
1843
2052
 
1844
2053
/* -------------------------------------------------------------------- */
1845
2054
/*      Create the new field.                                           */
1846
2055
/* -------------------------------------------------------------------- */
1847
2056
    poDS->FlushSoftTransaction();
1848
 
    hResult = PQexec(hPGConn, "BEGIN");
 
2057
    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
1849
2058
    OGRPGClearResult( hResult );
1850
2059
 
1851
 
    osCommand.Printf( "ALTER TABLE %s ADD COLUMN \"%s\" %s",
1852
 
                      pszSqlTableName, oField.GetNameRef(), szFieldType );
1853
 
    hResult = PQexec(hPGConn, osCommand);
 
2060
    osCommand.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
 
2061
                      pszSqlTableName, OGRPGEscapeColumnName(oField.GetNameRef()).c_str(),
 
2062
                      osFieldType.c_str() );
 
2063
    hResult = OGRPG_PQexec(hPGConn, osCommand);
1854
2064
    if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
1855
2065
    {
1856
2066
        CPLError( CE_Failure, CPLE_AppDefined,
1860
2070
 
1861
2071
        OGRPGClearResult( hResult );
1862
2072
 
1863
 
        hResult = PQexec( hPGConn, "ROLLBACK" );
 
2073
        hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
1864
2074
        OGRPGClearResult( hResult );
1865
2075
 
1866
2076
        return OGRERR_FAILURE;
1868
2078
 
1869
2079
    OGRPGClearResult( hResult );
1870
2080
 
1871
 
    hResult = PQexec(hPGConn, "COMMIT");
 
2081
    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
1872
2082
    OGRPGClearResult( hResult );
1873
2083
 
1874
2084
    poFeatureDefn->AddFieldDefn( &oField );
1877
2087
}
1878
2088
 
1879
2089
/************************************************************************/
 
2090
/*                            DeleteField()                             */
 
2091
/************************************************************************/
 
2092
 
 
2093
OGRErr OGRPGTableLayer::DeleteField( int iField )
 
2094
{
 
2095
    PGconn              *hPGConn = poDS->GetPGConn();
 
2096
    PGresult            *hResult = NULL;
 
2097
    CPLString           osCommand;
 
2098
 
 
2099
    GetLayerDefn();
 
2100
 
 
2101
    if( !bUpdateAccess )
 
2102
    {
 
2103
        CPLError( CE_Failure, CPLE_NotSupported,
 
2104
                  "Can't delete fields on a read-only datasource.");
 
2105
        return OGRERR_FAILURE;
 
2106
    }
 
2107
 
 
2108
    if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
 
2109
    {
 
2110
        CPLError( CE_Failure, CPLE_NotSupported,
 
2111
                  "Invalid field index");
 
2112
        return OGRERR_FAILURE;
 
2113
    }
 
2114
 
 
2115
    poDS->FlushSoftTransaction();
 
2116
 
 
2117
    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
 
2118
    OGRPGClearResult( hResult );
 
2119
 
 
2120
    osCommand.Printf( "ALTER TABLE %s DROP COLUMN %s",
 
2121
                      pszSqlTableName,
 
2122
                      OGRPGEscapeColumnName(poFeatureDefn->GetFieldDefn(iField)->GetNameRef()).c_str() );
 
2123
    hResult = OGRPG_PQexec(hPGConn, osCommand);
 
2124
    if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
 
2125
    {
 
2126
        CPLError( CE_Failure, CPLE_AppDefined,
 
2127
                  "%s\n%s",
 
2128
                  osCommand.c_str(),
 
2129
                  PQerrorMessage(hPGConn) );
 
2130
 
 
2131
        OGRPGClearResult( hResult );
 
2132
 
 
2133
        hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
 
2134
        OGRPGClearResult( hResult );
 
2135
 
 
2136
        return OGRERR_FAILURE;
 
2137
    }
 
2138
 
 
2139
    OGRPGClearResult( hResult );
 
2140
 
 
2141
    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
 
2142
    OGRPGClearResult( hResult );
 
2143
 
 
2144
    return poFeatureDefn->DeleteFieldDefn( iField );
 
2145
}
 
2146
 
 
2147
/************************************************************************/
 
2148
/*                           AlterFieldDefn()                           */
 
2149
/************************************************************************/
 
2150
 
 
2151
OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags )
 
2152
{
 
2153
    PGconn              *hPGConn = poDS->GetPGConn();
 
2154
    PGresult            *hResult = NULL;
 
2155
    CPLString           osCommand;
 
2156
 
 
2157
    GetLayerDefn();
 
2158
 
 
2159
    if( !bUpdateAccess )
 
2160
    {
 
2161
        CPLError( CE_Failure, CPLE_NotSupported,
 
2162
                  "Can't alter field definition on a read-only datasource.");
 
2163
        return OGRERR_FAILURE;
 
2164
    }
 
2165
 
 
2166
    if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
 
2167
    {
 
2168
        CPLError( CE_Failure, CPLE_NotSupported,
 
2169
                  "Invalid field index");
 
2170
        return OGRERR_FAILURE;
 
2171
    }
 
2172
 
 
2173
    OGRFieldDefn       *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
 
2174
    OGRFieldDefn        oField( poNewFieldDefn );
 
2175
 
 
2176
    poDS->FlushSoftTransaction();
 
2177
 
 
2178
    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
 
2179
    OGRPGClearResult( hResult );
 
2180
 
 
2181
    if (!(nFlags & ALTER_TYPE_FLAG))
 
2182
        oField.SetType(poFieldDefn->GetType());
 
2183
 
 
2184
    if (!(nFlags & ALTER_WIDTH_PRECISION_FLAG))
 
2185
    {
 
2186
        oField.SetWidth(poFieldDefn->GetWidth());
 
2187
        oField.SetPrecision(poFieldDefn->GetPrecision());
 
2188
    }
 
2189
 
 
2190
    if ((nFlags & ALTER_TYPE_FLAG) ||
 
2191
        (nFlags & ALTER_WIDTH_PRECISION_FLAG))
 
2192
    {
 
2193
        CPLString osFieldType = OGRPGTableLayerGetType(oField,
 
2194
                                                       bPreservePrecision,
 
2195
                                                       TRUE);
 
2196
        if (osFieldType.size() == 0)
 
2197
        {
 
2198
            hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
 
2199
            OGRPGClearResult( hResult );
 
2200
 
 
2201
            return OGRERR_FAILURE;
 
2202
        }
 
2203
 
 
2204
        osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s TYPE %s",
 
2205
                        pszSqlTableName,
 
2206
                        OGRPGEscapeColumnName(poFieldDefn->GetNameRef()).c_str(),
 
2207
                        osFieldType.c_str() );
 
2208
        hResult = OGRPG_PQexec(hPGConn, osCommand);
 
2209
        if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
 
2210
        {
 
2211
            CPLError( CE_Failure, CPLE_AppDefined,
 
2212
                    "%s\n%s",
 
2213
                    osCommand.c_str(),
 
2214
                    PQerrorMessage(hPGConn) );
 
2215
 
 
2216
            OGRPGClearResult( hResult );
 
2217
 
 
2218
            hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
 
2219
            OGRPGClearResult( hResult );
 
2220
 
 
2221
            return OGRERR_FAILURE;
 
2222
        }
 
2223
        OGRPGClearResult( hResult );
 
2224
    }
 
2225
 
 
2226
 
 
2227
    if( (nFlags & ALTER_NAME_FLAG) )
 
2228
    {
 
2229
        if (bLaunderColumnNames)
 
2230
        {
 
2231
            char    *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
 
2232
            oField.SetName( pszSafeName );
 
2233
            CPLFree( pszSafeName );
 
2234
        }
 
2235
 
 
2236
        if( EQUAL(oField.GetNameRef(),"oid") )
 
2237
        {
 
2238
            CPLError( CE_Warning, CPLE_AppDefined,
 
2239
                      "Renaming field 'oid' to 'oid_' to avoid conflict with internal oid field." );
 
2240
            oField.SetName( "oid_" );
 
2241
        }
 
2242
 
 
2243
        if ( strcmp(poFieldDefn->GetNameRef(), oField.GetNameRef()) != 0 )
 
2244
        {
 
2245
            osCommand.Printf( "ALTER TABLE %s RENAME COLUMN %s TO %s",
 
2246
                            pszSqlTableName,
 
2247
                            OGRPGEscapeColumnName(poFieldDefn->GetNameRef()).c_str(),
 
2248
                            OGRPGEscapeColumnName(oField.GetNameRef()).c_str() );
 
2249
            hResult = OGRPG_PQexec(hPGConn, osCommand);
 
2250
            if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
 
2251
            {
 
2252
                CPLError( CE_Failure, CPLE_AppDefined,
 
2253
                        "%s\n%s",
 
2254
                        osCommand.c_str(),
 
2255
                        PQerrorMessage(hPGConn) );
 
2256
 
 
2257
                OGRPGClearResult( hResult );
 
2258
 
 
2259
                hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
 
2260
                OGRPGClearResult( hResult );
 
2261
 
 
2262
                return OGRERR_FAILURE;
 
2263
            }
 
2264
            OGRPGClearResult( hResult );
 
2265
        }
 
2266
    }
 
2267
 
 
2268
    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
 
2269
    OGRPGClearResult( hResult );
 
2270
 
 
2271
    if (nFlags & ALTER_NAME_FLAG)
 
2272
        poFieldDefn->SetName(oField.GetNameRef());
 
2273
    if (nFlags & ALTER_TYPE_FLAG)
 
2274
        poFieldDefn->SetType(oField.GetType());
 
2275
    if (nFlags & ALTER_WIDTH_PRECISION_FLAG)
 
2276
    {
 
2277
        poFieldDefn->SetWidth(oField.GetWidth());
 
2278
        poFieldDefn->SetPrecision(oField.GetPrecision());
 
2279
    }
 
2280
 
 
2281
    return OGRERR_NONE;
 
2282
 
 
2283
}
 
2284
 
 
2285
/************************************************************************/
1880
2286
/*                             GetFeature()                             */
1881
2287
/************************************************************************/
1882
2288
 
1883
2289
OGRFeature *OGRPGTableLayer::GetFeature( long nFeatureId )
1884
2290
 
1885
2291
{
 
2292
    GetLayerDefn();
 
2293
 
1886
2294
    if( pszFIDColumn == NULL )
1887
2295
        return OGRLayer::GetFeature( nFeatureId );
1888
2296
 
1905
2313
 
1906
2314
    osCommand.Printf(
1907
2315
             "DECLARE getfeaturecursor %s for "
1908
 
             "SELECT %s FROM %s WHERE \"%s\" = %ld",
 
2316
             "SELECT %s FROM %s WHERE %s = %ld",
1909
2317
              ( poDS->bUseBinaryCursor ) ? "BINARY CURSOR" : "CURSOR",
1910
 
             osFieldList.c_str(), pszSqlTableName, pszFIDColumn,
 
2318
             osFieldList.c_str(), pszSqlTableName, OGRPGEscapeColumnName(pszFIDColumn).c_str(),
1911
2319
             nFeatureId );
1912
2320
 
1913
 
    hResult = PQexec(hPGConn, osCommand.c_str() );
 
2321
    hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
1914
2322
 
1915
2323
    if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
1916
2324
    {
1917
2325
        OGRPGClearResult( hResult );
1918
2326
 
1919
 
        hResult = PQexec(hPGConn, "FETCH ALL in getfeaturecursor" );
 
2327
        hResult = OGRPG_PQexec(hPGConn, "FETCH ALL in getfeaturecursor" );
1920
2328
 
1921
2329
        if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK )
1922
2330
        {
1942
2350
            }
1943
2351
        }
1944
2352
    }
 
2353
    else if ( hResult && PQresultStatus(hResult) == PGRES_FATAL_ERROR )
 
2354
    {
 
2355
        CPLError( CE_Failure, CPLE_AppDefined,
 
2356
                  "%s", PQresultErrorMessage( hResult ) );
 
2357
    }
1945
2358
 
1946
2359
/* -------------------------------------------------------------------- */
1947
2360
/*      Cleanup                                                         */
1948
2361
/* -------------------------------------------------------------------- */
1949
2362
    OGRPGClearResult( hResult );
1950
2363
 
1951
 
    hResult = PQexec(hPGConn, "CLOSE getfeaturecursor");
 
2364
    hResult = OGRPG_PQexec(hPGConn, "CLOSE getfeaturecursor");
1952
2365
    OGRPGClearResult( hResult );
1953
2366
 
1954
2367
    poDS->FlushSoftTransaction();
1963
2376
int OGRPGTableLayer::GetFeatureCount( int bForce )
1964
2377
 
1965
2378
{
 
2379
    GetLayerDefn();
 
2380
 
1966
2381
    if( TestCapability(OLCFastFeatureCount) == FALSE )
1967
2382
        return OGRPGLayer::GetFeatureCount( bForce );
1968
2383
 
1981
2396
        "SELECT count(*) FROM %s %s",
1982
2397
        pszSqlTableName, osWHERE.c_str() );
1983
2398
 
1984
 
    hResult = PQexec(hPGConn, osCommand);
 
2399
    hResult = OGRPG_PQexec(hPGConn, osCommand);
1985
2400
    if( hResult != NULL && PQresultStatus(hResult) == PGRES_TUPLES_OK )
1986
2401
        nCount = atoi(PQgetvalue(hResult,0,0));
1987
2402
    else
1995
2410
/*                           GetSpatialRef()                            */
1996
2411
/*                                                                      */
1997
2412
/*      We override this to try and fetch the table SRID from the       */
1998
 
/*      geometry_columns table if the srsid is -2 (meaning we           */
1999
 
/*      haven't yet even looked for it).                                */
 
2413
/*      geometry_columns table if the srsid is UNDETERMINED_SRID        */
 
2414
/*      (meaning we haven't yet even looked for it).                    */
2000
2415
/************************************************************************/
2001
2416
 
2002
2417
OGRSpatialReference *OGRPGTableLayer::GetSpatialRef()
2003
2418
 
2004
2419
{
2005
 
    if( nSRSId == -2 )
 
2420
    if( nSRSId == UNDETERMINED_SRID )
2006
2421
    {
2007
2422
        PGconn      *hPGConn = poDS->GetPGConn();
2008
2423
        PGresult    *hResult = NULL;
2009
2424
        CPLString    osCommand;
2010
2425
 
2011
 
        nSRSId = -1;
 
2426
        nSRSId = poDS->GetUndefinedSRID();
2012
2427
 
2013
2428
        poDS->SoftStartTransaction();
2014
2429
 
2015
 
        if (bHasPostGISGeography)
2016
 
        {
2017
 
            osCommand.Printf(
2018
 
                     "SELECT srid FROM geography_columns "
2019
 
                     "WHERE f_table_name = '%s'",
2020
 
                     (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName);
2021
 
 
2022
 
            if (pszGeomColumn)
2023
 
            {
2024
 
                osCommand += CPLString().Printf(" AND f_geography_column = '%s'", pszGeomColumn);
2025
 
            }
2026
 
        }
2027
 
        else
2028
 
        {
2029
 
            osCommand.Printf(
2030
 
                     "SELECT srid FROM geometry_columns "
2031
 
                     "WHERE f_table_name = '%s'",
2032
 
                     (pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName);
2033
 
 
2034
 
            if (pszGeomColumn)
2035
 
            {
2036
 
                osCommand += CPLString().Printf(" AND f_geometry_column = '%s'", pszGeomColumn);
2037
 
            }
 
2430
        osCommand.Printf(
 
2431
                    "SELECT srid FROM geometry_columns "
 
2432
                    "WHERE f_table_name = '%s'",
 
2433
                    pszTableName);
 
2434
 
 
2435
        if (pszGeomColumn)
 
2436
        {
 
2437
            osCommand += CPLString().Printf(" AND f_geometry_column = '%s'", pszGeomColumn);
2038
2438
        }
2039
2439
 
2040
2440
        if (pszSchemaName)
2042
2442
            osCommand += CPLString().Printf(" AND f_table_schema = '%s'", pszSchemaName);
2043
2443
        }
2044
2444
 
2045
 
        hResult = PQexec(hPGConn, osCommand.c_str() );
 
2445
        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
2046
2446
 
2047
2447
        if( hResult
2048
2448
            && PQresultStatus(hResult) == PGRES_TUPLES_OK
2070
2470
{
2071
2471
    CPLString   osCommand;
2072
2472
 
 
2473
    GetLayerDefn();
 
2474
 
 
2475
    const char* pszExtentFct;
 
2476
    if (poDS->sPostGISVersion.nMajor >= 2)
 
2477
        pszExtentFct = "ST_Extent";
 
2478
    else
 
2479
        pszExtentFct = "Extent";
 
2480
 
2073
2481
    if ( TestCapability(OLCFastGetExtent) )
2074
2482
    {
2075
 
        osCommand.Printf( "SELECT Extent(\"%s\") FROM %s", 
2076
 
                          pszGeomColumn, pszSqlTableName );
 
2483
        osCommand.Printf( "SELECT %s(%s) FROM %s", pszExtentFct,
 
2484
                          OGRPGEscapeColumnName(pszGeomColumn).c_str(), pszSqlTableName );
2077
2485
    }
2078
2486
    else if ( bHasPostGISGeography )
2079
2487
    {
2080
2488
        /* Probably not very efficient, but more efficient than client-side implementation */
2081
 
        osCommand.Printf( "SELECT Extent(ST_GeomFromWKB(ST_AsBinary(\"%s\"))) FROM %s", 
2082
 
                          pszGeomColumn, pszSqlTableName );
 
2489
        osCommand.Printf( "SELECT %s(ST_GeomFromWKB(ST_AsBinary(%s))) FROM %s",
 
2490
                          pszExtentFct,
 
2491
                          OGRPGEscapeColumnName(pszGeomColumn).c_str(), pszSqlTableName );
2083
2492
    }
2084
2493
 
2085
2494
    return RunGetExtentRequest(psExtent, bForce, osCommand);
2107
2516
             pszSqlTableName, osFields.c_str() );
2108
2517
 
2109
2518
    PGconn *hPGConn = poDS->GetPGConn();
2110
 
    PGresult *hResult = PQexec(hPGConn, pszCommand);
 
2519
    PGresult *hResult = OGRPG_PQexec(hPGConn, pszCommand);
2111
2520
 
2112
2521
    if ( !hResult || (PQresultStatus(hResult) != PGRES_COPY_IN))
2113
2522
    {
2200
2609
 
2201
2610
    if( bHasFid && poFeatureDefn->GetFieldIndex( pszFIDColumn ) != -1 )
2202
2611
    {
2203
 
        osFieldList += "\"";
2204
 
        osFieldList += pszFIDColumn;
2205
 
        osFieldList += "\"";
 
2612
        osFieldList += OGRPGEscapeColumnName(pszFIDColumn);
2206
2613
    }
2207
2614
 
2208
2615
    if( pszGeomColumn )
2210
2617
        if( strlen(osFieldList) > 0 )
2211
2618
            osFieldList += ", ";
2212
2619
 
2213
 
        osFieldList += "\"";
2214
 
        osFieldList += pszGeomColumn;
2215
 
        osFieldList += "\"";
 
2620
        osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
2216
2621
    }
2217
2622
 
2218
2623
    for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
2222
2627
        if( strlen(osFieldList) > 0 )
2223
2628
            osFieldList += ", ";
2224
2629
 
2225
 
        osFieldList += "\"";
2226
 
        osFieldList += pszName;
2227
 
        osFieldList += "\"" ;
 
2630
        osFieldList += OGRPGEscapeColumnName(pszName);
2228
2631
    }
2229
2632
 
2230
2633
    return osFieldList;
2261
2664
                 OGRGeometryTypeToName(poFeatureDefn->GetGeomType()));
2262
2665
    }
2263
2666
}
 
2667
 
 
2668
/************************************************************************/
 
2669
/*                  GetLayerDefnCanReturnNULL()                         */
 
2670
/************************************************************************/
 
2671
 
 
2672
OGRFeatureDefn * OGRPGTableLayer::GetLayerDefnCanReturnNULL()
 
2673
{
 
2674
    if (poFeatureDefn)
 
2675
        return poFeatureDefn;
 
2676
 
 
2677
    poFeatureDefn = ReadTableDefinition();
 
2678
 
 
2679
    if( poFeatureDefn )
 
2680
    {
 
2681
        ResetReading();
 
2682
    }
 
2683
 
 
2684
    return poFeatureDefn;
 
2685
}
 
2686
 
 
2687
/************************************************************************/
 
2688
/*                         GetLayerDefn()                              */
 
2689
/************************************************************************/
 
2690
 
 
2691
OGRFeatureDefn * OGRPGTableLayer::GetLayerDefn()
 
2692
{
 
2693
    if (poFeatureDefn)
 
2694
        return poFeatureDefn;
 
2695
 
 
2696
    GetLayerDefnCanReturnNULL();
 
2697
    if (poFeatureDefn == NULL)
 
2698
    {
 
2699
        poFeatureDefn = new OGRFeatureDefn(pszTableName);
 
2700
        poFeatureDefn->Reference();
 
2701
    }
 
2702
    return poFeatureDefn;
 
2703
}