LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpgdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 954 822 86.2 %
Date: 2012-12-26 Functions: 50 37 74.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpgdatasource.cpp 25148 2012-10-17 18:04:31Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGRPGDataSource class.
       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 <string.h>
      31                 : #include "ogr_pg.h"
      32                 : #include "cpl_conv.h"
      33                 : #include "cpl_string.h"
      34                 : #include "cpl_hash_set.h"
      35                 : 
      36                 : #define PQexec this_is_an_error
      37                 : 
      38                 : CPL_CVSID("$Id: ogrpgdatasource.cpp 25148 2012-10-17 18:04:31Z rouault $");
      39                 : 
      40                 : static void OGRPGNoticeProcessor( void *arg, const char * pszMessage );
      41                 : 
      42                 : /************************************************************************/
      43                 : /*                          OGRPGDataSource()                           */
      44                 : /************************************************************************/
      45                 : 
      46             327 : OGRPGDataSource::OGRPGDataSource()
      47                 : 
      48                 : {
      49             327 :     pszName = NULL;
      50             327 :     pszDBName = NULL;
      51             327 :     papoLayers = NULL;
      52             327 :     nLayers = 0;
      53             327 :     hPGConn = NULL;
      54             327 :     bHavePostGIS = FALSE;
      55             327 :     bHaveGeography = FALSE;
      56             327 :     bUseBinaryCursor = FALSE;
      57             327 :     nSoftTransactionLevel = 0;
      58             327 :     bBinaryTimeFormatIsInt8 = FALSE;
      59             327 :     bUseEscapeStringSyntax = FALSE;
      60                 :     
      61             327 :     nGeometryOID = (Oid) 0;
      62             327 :     nGeographyOID = (Oid) 0;
      63                 : 
      64             327 :     nKnownSRID = 0;
      65             327 :     panSRID = NULL;
      66             327 :     papoSRS = NULL;
      67                 : 
      68             327 :     poLayerInCopyMode = NULL;
      69             327 :     nUndefinedSRID = -1; /* actual value will be autotected if PostGIS >= 2.0 detected */
      70             327 : }
      71                 : 
      72                 : /************************************************************************/
      73                 : /*                          ~OGRPGDataSource()                          */
      74                 : /************************************************************************/
      75                 : 
      76             327 : OGRPGDataSource::~OGRPGDataSource()
      77                 : 
      78                 : {
      79                 :     int         i;
      80                 : 
      81             327 :     FlushSoftTransaction();
      82                 : 
      83             327 :     CPLFree( pszName );
      84             327 :     CPLFree( pszDBName );
      85                 : 
      86           16490 :     for( i = 0; i < nLayers; i++ )
      87           16163 :         delete papoLayers[i];
      88                 : 
      89             327 :     CPLFree( papoLayers );
      90                 : 
      91             327 :     if( hPGConn != NULL )
      92                 :     {
      93                 :         /* XXX - mloskot: After the connection is closed, valgrind still
      94                 :          * reports 36 bytes definitely lost, somewhere in the libpq.
      95                 :          */
      96             114 :         PQfinish( hPGConn );
      97             114 :         hPGConn = NULL;
      98                 :     }
      99                 : 
     100             332 :     for( i = 0; i < nKnownSRID; i++ )
     101                 :     {
     102               5 :         if( papoSRS[i] != NULL )
     103               5 :             papoSRS[i]->Release();
     104                 :     }
     105             327 :     CPLFree( panSRID );
     106             327 :     CPLFree( papoSRS );
     107             327 : }
     108                 : 
     109                 : /************************************************************************/
     110                 : /*                         GetCurrentSchema()                           */
     111                 : /************************************************************************/
     112                 : 
     113             114 : CPLString OGRPGDataSource::GetCurrentSchema()
     114                 : {
     115                 :     /* -------------------------------------------- */
     116                 :     /*          Get the current schema              */
     117                 :     /* -------------------------------------------- */
     118             114 :     PGresult    *hResult = OGRPG_PQexec(hPGConn,"SELECT current_schema()");
     119             114 :     if ( hResult && PQntuples(hResult) == 1 && !PQgetisnull(hResult,0,0) )
     120                 :     {
     121             114 :         osCurrentSchema = PQgetvalue(hResult,0,0);
     122                 :     }
     123             114 :     OGRPGClearResult( hResult );
     124                 : 
     125             114 :     return osCurrentSchema;
     126                 : }
     127                 : 
     128                 : /************************************************************************/
     129                 : /*                      OGRPGDecodeVersionString()                      */
     130                 : /************************************************************************/
     131                 : 
     132             195 : void OGRPGDataSource::OGRPGDecodeVersionString(PGver* psVersion, const char* pszVer)
     133                 : {
     134                 :     GUInt32 iLen;
     135                 :     const char* ptr;
     136                 :     char szNum[25];
     137                 :     char szVer[10];
     138                 : 
     139             195 :     while ( *pszVer == ' ' ) pszVer++;
     140                 : 
     141             195 :     ptr = pszVer;
     142                 :     // get Version string
     143             195 :     while (*ptr && *ptr != ' ') ptr++;
     144             195 :     iLen = ptr-pszVer;
     145             195 :     if ( iLen > sizeof(szVer) - 1 ) iLen = sizeof(szVer) - 1;
     146             195 :     strncpy(szVer,pszVer,iLen);
     147             195 :     szVer[iLen] = '\0';
     148                 : 
     149             195 :     ptr = pszVer = szVer;
     150                 : 
     151                 :     // get Major number
     152             195 :     while (*ptr && *ptr != '.') ptr++;
     153             195 :     iLen = ptr-pszVer;
     154             195 :     if ( iLen > sizeof(szNum) - 1) iLen = sizeof(szNum) - 1;
     155             195 :     strncpy(szNum,pszVer,iLen);
     156             195 :     szNum[iLen] = '\0';
     157             195 :     psVersion->nMajor = atoi(szNum);
     158                 : 
     159             195 :     if (*ptr == 0)
     160               0 :         return;
     161             195 :     pszVer = ++ptr;
     162                 : 
     163                 :     // get Minor number
     164             195 :     while (*ptr && *ptr != '.') ptr++;
     165             195 :     iLen = ptr-pszVer;
     166             195 :     if ( iLen > sizeof(szNum) - 1) iLen = sizeof(szNum) - 1;
     167             195 :     strncpy(szNum,pszVer,iLen);
     168             195 :     szNum[iLen] = '\0';
     169             195 :     psVersion->nMinor = atoi(szNum);
     170                 : 
     171                 : 
     172             195 :     if ( *ptr )
     173                 :     {
     174             114 :         pszVer = ++ptr;
     175                 : 
     176                 :         // get Release number
     177             114 :         while (*ptr && *ptr != '.') ptr++;
     178             114 :         iLen = ptr-pszVer;
     179             114 :         if ( iLen > sizeof(szNum) - 1) iLen = sizeof(szNum) - 1;
     180             114 :         strncpy(szNum,pszVer,iLen);
     181             114 :         szNum[iLen] = '\0';
     182             114 :         psVersion->nRelease = atoi(szNum);
     183                 :     }
     184                 : 
     185                 : }
     186                 : 
     187                 : 
     188                 : /************************************************************************/
     189                 : /*                     One entry for each PG table                      */
     190                 : /************************************************************************/
     191                 : 
     192                 : typedef struct
     193                 : {
     194                 :     char* pszName;
     195                 :     char* pszGeomType;
     196                 :     int   nCoordDimension;
     197                 :     int   nSRID;
     198                 :     PostgisType   ePostgisType;
     199                 : } PGGeomColumnDesc;
     200                 : 
     201                 : typedef struct
     202                 : {
     203                 :     char* pszTableName;
     204                 :     char* pszSchemaName;
     205                 :     int   nGeomColumnCount;
     206                 :     PGGeomColumnDesc* pasGeomColumns;   /* list of geometry columns */
     207                 :     int   bDerivedInfoAdded;            /* set to TRUE if it derives from another table */
     208                 : } PGTableEntry;
     209                 : 
     210           91725 : static unsigned long OGRPGHashTableEntry(const void * _psTableEntry)
     211                 : {
     212           91725 :     const PGTableEntry* psTableEntry = (PGTableEntry*)_psTableEntry;
     213                 :     return CPLHashSetHashStr(CPLString().Printf("%s.%s",
     214           91725 :                              psTableEntry->pszSchemaName, psTableEntry->pszTableName));
     215                 : }
     216                 : 
     217           36186 : static int OGRPGEqualTableEntry(const void* _psTableEntry1, const void* _psTableEntry2)
     218                 : {
     219           36186 :     const PGTableEntry* psTableEntry1 = (PGTableEntry*)_psTableEntry1;
     220           36186 :     const PGTableEntry* psTableEntry2 = (PGTableEntry*)_psTableEntry2;
     221                 :     return strcmp(psTableEntry1->pszTableName, psTableEntry2->pszTableName) == 0 &&
     222           36186 :            strcmp(psTableEntry1->pszSchemaName, psTableEntry2->pszSchemaName) == 0;
     223                 : }
     224                 : 
     225           22853 : static void OGRPGTableEntryAddGeomColumn(PGTableEntry* psTableEntry,
     226                 :                                          const char* pszName,
     227                 :                                          const char* pszGeomType = NULL,
     228                 :                                          int nCoordDimension = 0,
     229                 :                                          int nSRID = UNDETERMINED_SRID,
     230                 :                                          PostgisType ePostgisType = GEOM_TYPE_UNKNOWN)
     231                 : {
     232                 :     psTableEntry->pasGeomColumns = (PGGeomColumnDesc*)
     233                 :         CPLRealloc(psTableEntry->pasGeomColumns,
     234           22853 :                sizeof(PGGeomColumnDesc) * (psTableEntry->nGeomColumnCount + 1));
     235           22853 :     psTableEntry->pasGeomColumns[psTableEntry->nGeomColumnCount].pszName = CPLStrdup(pszName);
     236           22853 :     psTableEntry->pasGeomColumns[psTableEntry->nGeomColumnCount].pszGeomType = (pszGeomType) ? CPLStrdup(pszGeomType) : NULL;
     237           22853 :     psTableEntry->pasGeomColumns[psTableEntry->nGeomColumnCount].nCoordDimension = nCoordDimension;
     238           22853 :     psTableEntry->pasGeomColumns[psTableEntry->nGeomColumnCount].nSRID = nSRID;
     239           22853 :     psTableEntry->pasGeomColumns[psTableEntry->nGeomColumnCount].ePostgisType = ePostgisType;
     240           22853 :     psTableEntry->nGeomColumnCount ++;
     241           22853 : }
     242                 : 
     243             308 : static void OGRPGTableEntryAddGeomColumn(PGTableEntry* psTableEntry,
     244                 :                                          const PGGeomColumnDesc* psGeomColumnDesc)
     245                 : {
     246                 :     OGRPGTableEntryAddGeomColumn(psTableEntry,
     247                 :                                  psGeomColumnDesc->pszName,
     248                 :                                  psGeomColumnDesc->pszGeomType,
     249                 :                                  psGeomColumnDesc->nCoordDimension,
     250                 :                                  psGeomColumnDesc->nSRID,
     251             308 :                                  psGeomColumnDesc->ePostgisType);
     252             308 : }
     253                 : 
     254           33228 : static void OGRPGFreeTableEntry(void * _psTableEntry)
     255                 : {
     256           33228 :     PGTableEntry* psTableEntry = (PGTableEntry*)_psTableEntry;
     257           33228 :     CPLFree(psTableEntry->pszTableName);
     258           33228 :     CPLFree(psTableEntry->pszSchemaName);
     259                 :     int i;
     260           56081 :     for(i=0;i<psTableEntry->nGeomColumnCount;i++)
     261                 :     {
     262           22853 :         CPLFree(psTableEntry->pasGeomColumns[i].pszName);
     263           22853 :         CPLFree(psTableEntry->pasGeomColumns[i].pszGeomType);
     264                 :     }
     265           33228 :     CPLFree(psTableEntry->pasGeomColumns);
     266           33228 :     CPLFree(psTableEntry);
     267           33228 : }
     268                 : 
     269           17187 : static PGTableEntry* OGRPGFindTableEntry(CPLHashSet* hSetTables,
     270                 :                                          const char* pszTableName,
     271                 :                                          const char* pszSchemaName)
     272                 : {
     273                 :     PGTableEntry sEntry;
     274           17187 :     sEntry.pszTableName = (char*) pszTableName;
     275           17187 :     sEntry.pszSchemaName = (char*) pszSchemaName;
     276           17187 :     return (PGTableEntry*) CPLHashSetLookup(hSetTables, &sEntry);
     277                 : }
     278                 : 
     279           16567 : static PGTableEntry* OGRPGAddTableEntry(CPLHashSet* hSetTables,
     280                 :                                         const char* pszTableName,
     281                 :                                         const char* pszSchemaName)
     282                 : {
     283           16567 :     PGTableEntry* psEntry = (PGTableEntry*) CPLCalloc(1, sizeof(PGTableEntry));
     284           16567 :     psEntry->pszTableName = CPLStrdup(pszTableName);
     285           16567 :     psEntry->pszSchemaName = CPLStrdup(pszSchemaName);
     286                 : 
     287           16567 :     CPLHashSetInsert(hSetTables, psEntry);
     288                 : 
     289           16567 :     return psEntry;
     290                 : }
     291                 : 
     292                 : /************************************************************************/
     293                 : /*                                Open()                                */
     294                 : /************************************************************************/
     295                 : 
     296             327 : int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
     297                 :                               int bTestOpen )
     298                 : 
     299                 : {
     300             327 :     CPLAssert( nLayers == 0 );
     301                 : 
     302                 : /* -------------------------------------------------------------------- */
     303                 : /*      Verify postgresql prefix.                                       */
     304                 : /* -------------------------------------------------------------------- */
     305             327 :     if( EQUALN(pszNewName,"PGB:",4) )
     306                 :     {
     307               4 :         bUseBinaryCursor = TRUE;
     308               4 :         CPLDebug("PG","BINARY cursor is used for geometry fetching");
     309                 :     }
     310                 :     else
     311             323 :     if( !EQUALN(pszNewName,"PG:",3) )
     312                 :     {
     313             213 :         if( !bTestOpen )
     314                 :             CPLError( CE_Failure, CPLE_AppDefined,
     315                 :                       "%s does not conform to PostgreSQL naming convention,"
     316               0 :                       " PG:*\n", pszNewName );
     317             213 :         return FALSE;
     318                 :     }
     319                 : 
     320             114 :     pszName = CPLStrdup( pszNewName );
     321             114 :     char* pszConnectionName = CPLStrdup(pszName);
     322                 : 
     323                 : /* -------------------------------------------------------------------- */
     324                 : /*      Determine if the connection string contains an optional         */
     325                 : /*      ACTIVE_SCHEMA portion. If so, parse it out.                     */
     326                 : /* -------------------------------------------------------------------- */
     327                 :     char             *pszActiveSchemaStart;
     328             114 :     CPLString         osActiveSchema;
     329             114 :     pszActiveSchemaStart = strstr(pszConnectionName, "active_schema=");
     330             114 :     if (pszActiveSchemaStart == NULL)
     331             112 :         pszActiveSchemaStart = strstr(pszConnectionName, "ACTIVE_SCHEMA=");
     332             114 :     if (pszActiveSchemaStart != NULL)
     333                 :     {
     334                 :         char           *pszActiveSchema;
     335               2 :         const char     *pszEnd = NULL;
     336                 : 
     337               2 :         pszActiveSchema = CPLStrdup( pszActiveSchemaStart + strlen("active_schema=") );
     338                 : 
     339               2 :         pszEnd = strchr(pszActiveSchemaStart, ' ');
     340               2 :         if( pszEnd == NULL )
     341               2 :             pszEnd = pszConnectionName + strlen(pszConnectionName);
     342                 : 
     343                 :         // Remove ACTIVE_SCHEMA=xxxxx from pszConnectionName string
     344               2 :         memmove( pszActiveSchemaStart, pszEnd, strlen(pszEnd) + 1 );
     345                 : 
     346               2 :         pszActiveSchema[pszEnd - pszActiveSchemaStart - strlen("active_schema=")] = '\0';
     347                 : 
     348               2 :         osActiveSchema = pszActiveSchema;
     349               2 :         CPLFree(pszActiveSchema);
     350                 :     }
     351                 :     else
     352                 :     {
     353             112 :         osActiveSchema = "public";
     354                 :     }
     355                 : 
     356                 : /* -------------------------------------------------------------------- */
     357                 : /*      Determine if the connection string contains an optional         */
     358                 : /*      SCHEMAS portion. If so, parse it out.                           */
     359                 : /* -------------------------------------------------------------------- */
     360                 :     char             *pszSchemasStart;
     361             114 :     char            **papszSchemaList = NULL;
     362             114 :     pszSchemasStart = strstr(pszConnectionName, "schemas=");
     363             114 :     if (pszSchemasStart == NULL)
     364             110 :         pszSchemasStart = strstr(pszConnectionName, "SCHEMAS=");
     365             114 :     if (pszSchemasStart != NULL)
     366                 :     {
     367                 :         char           *pszSchemas;
     368               4 :         const char     *pszEnd = NULL;
     369                 : 
     370               4 :         pszSchemas = CPLStrdup( pszSchemasStart + strlen("schemas=") );
     371                 : 
     372               4 :         pszEnd = strchr(pszSchemasStart, ' ');
     373               4 :         if( pszEnd == NULL )
     374               4 :             pszEnd = pszConnectionName + strlen(pszConnectionName);
     375                 : 
     376                 :         // Remove SCHEMAS=xxxxx from pszConnectionName string
     377               4 :         memmove( pszSchemasStart, pszEnd, strlen(pszEnd) + 1 );
     378                 : 
     379               4 :         pszSchemas[pszEnd - pszSchemasStart - strlen("schemas=")] = '\0';
     380                 : 
     381               4 :         papszSchemaList = CSLTokenizeString2( pszSchemas, ",", 0 );
     382                 : 
     383               4 :         CPLFree(pszSchemas);
     384                 : 
     385                 :         /* If there is only one schema specified, make it the active schema */
     386               4 :         if (CSLCount(papszSchemaList) == 1)
     387                 :         {
     388               2 :             osActiveSchema = papszSchemaList[0];
     389                 :         }
     390                 :     }
     391                 : 
     392                 : /* -------------------------------------------------------------------- */
     393                 : /*      Determine if the connection string contains an optional         */
     394                 : /*      TABLES portion. If so, parse it out. The expected               */
     395                 : /*      connection string in this case will be, e.g.:                   */
     396                 : /*                                                                      */
     397                 : /*        'PG:dbname=warmerda user=warmerda tables=s1.t1,[s2.t2,...]    */
     398                 : /*              - where sN is schema and tN is table name               */
     399                 : /*      We must also strip this information from the connection         */
     400                 : /*      string; PQconnectdb() does not like unknown directives          */
     401                 : /* -------------------------------------------------------------------- */
     402             114 :     PGTableEntry **papsTables = NULL;
     403             114 :     int            nTableCount = 0;
     404                 : 
     405                 :     char             *pszTableStart;
     406             114 :     pszTableStart = strstr(pszConnectionName, "tables=");
     407             114 :     if (pszTableStart == NULL)
     408             111 :         pszTableStart = strstr(pszConnectionName, "TABLES=");
     409                 : 
     410             114 :     if( pszTableStart != NULL )
     411                 :     {
     412                 :         char          **papszTableList;
     413                 :         char           *pszTableSpec;
     414               5 :         const char     *pszEnd = NULL;
     415                 :         int             i;
     416                 : 
     417               5 :         pszTableSpec = CPLStrdup( pszTableStart + 7 );
     418                 : 
     419               5 :         pszEnd = strchr(pszTableStart, ' ');
     420               5 :         if( pszEnd == NULL )
     421               5 :             pszEnd = pszConnectionName + strlen(pszConnectionName);
     422                 : 
     423                 :         // Remove TABLES=xxxxx from pszConnectionName string
     424               5 :         memmove( pszTableStart, pszEnd, strlen(pszEnd) + 1 );
     425                 : 
     426               5 :         pszTableSpec[pszEnd - pszTableStart - 7] = '\0';
     427               5 :         papszTableList = CSLTokenizeString2( pszTableSpec, ",", 0 );
     428                 : 
     429              12 :         for( i = 0; i < CSLCount(papszTableList); i++ )
     430                 :         {
     431                 :             char      **papszQualifiedParts;
     432                 : 
     433                 :             // Get schema and table name
     434               7 :             papszQualifiedParts = CSLTokenizeString2( papszTableList[i],
     435              14 :                                                       ".", 0 );
     436               7 :             int nParts = CSLCount( papszQualifiedParts );
     437                 : 
     438               7 :             if( nParts == 1 || nParts == 2 )
     439                 :             {
     440                 :                 /* Find the geometry column name if specified */
     441               7 :                 char* pszGeomColumnName = NULL;
     442               7 :                 char* pos = strchr(papszQualifiedParts[CSLCount( papszQualifiedParts ) - 1], '(');
     443               7 :                 if (pos != NULL)
     444                 :                 {
     445               1 :                     *pos = '\0';
     446               1 :                     pszGeomColumnName = pos+1;
     447               1 :                     int len = strlen(pszGeomColumnName);
     448               1 :                     if (len > 0)
     449               1 :                         pszGeomColumnName[len - 1] = '\0';
     450                 :                 }
     451                 : 
     452               7 :                 papsTables = (PGTableEntry**)CPLRealloc(papsTables, sizeof(PGTableEntry*) * (nTableCount + 1));
     453               7 :                 papsTables[nTableCount] = (PGTableEntry*) CPLCalloc(1, sizeof(PGTableEntry));
     454               7 :                 if (pszGeomColumnName)
     455               1 :                     OGRPGTableEntryAddGeomColumn(papsTables[nTableCount], pszGeomColumnName);
     456                 : 
     457               7 :                 if( nParts == 2 )
     458                 :                 {
     459               0 :                     papsTables[nTableCount]->pszSchemaName = CPLStrdup( papszQualifiedParts[0] );
     460               0 :                     papsTables[nTableCount]->pszTableName = CPLStrdup( papszQualifiedParts[1] );
     461                 :                 }
     462                 :                 else
     463                 :                 {
     464               7 :                     papsTables[nTableCount]->pszSchemaName = CPLStrdup( osActiveSchema.c_str());
     465               7 :                     papsTables[nTableCount]->pszTableName = CPLStrdup( papszQualifiedParts[0] );
     466                 :                 }
     467               7 :                 nTableCount ++;
     468                 :             }
     469                 : 
     470               7 :             CSLDestroy(papszQualifiedParts);
     471                 :         }
     472                 : 
     473               5 :         CSLDestroy(papszTableList);
     474               5 :         CPLFree(pszTableSpec);
     475                 :     }
     476                 : 
     477                 : 
     478             114 :     CPLString      osCurrentSchema;
     479             114 :     CPLHashSet    *hSetTables = NULL;
     480             114 :     int            bRet = FALSE;
     481             114 :     int            bListAllTables = CSLTestBoolean(CPLGetConfigOption("PG_LIST_ALL_TABLES", "NO"));
     482             114 :     PGresult      *hResult = NULL;
     483                 : 
     484                 : /* -------------------------------------------------------------------- */
     485                 : /*      Try to establish connection.                                    */
     486                 : /* -------------------------------------------------------------------- */
     487             114 :     hPGConn = PQconnectdb( pszConnectionName + (bUseBinaryCursor ? 4 : 3) );
     488             114 :     CPLFree(pszConnectionName);
     489             114 :     pszConnectionName = NULL;
     490                 : 
     491             114 :     if( hPGConn == NULL || PQstatus(hPGConn) == CONNECTION_BAD )
     492                 :     {
     493                 :         CPLError( CE_Failure, CPLE_AppDefined,
     494                 :                   "PQconnectdb failed.\n%s",
     495               0 :                   PQerrorMessage(hPGConn) );
     496                 : 
     497               0 :         PQfinish(hPGConn);
     498               0 :         hPGConn = NULL;
     499                 : 
     500               0 :         goto end;
     501                 :     }
     502                 : 
     503             114 :     bDSUpdate = bUpdate;
     504                 : 
     505                 : /* -------------------------------------------------------------------- */
     506                 : /*      Set the encoding to UTF8 as the driver advertizes UTF8          */
     507                 : /*      unless PGCLIENTENCODING is defined                              */
     508                 : /* -------------------------------------------------------------------- */
     509             114 :     if (CPLGetConfigOption("PGCLIENTENCODING", NULL) == NULL)
     510                 :     {
     511             112 :         const char* encoding = "UNICODE";
     512             112 :         if (PQsetClientEncoding(hPGConn, encoding) == -1)
     513                 :         {
     514                 :             CPLError( CE_Warning, CPLE_AppDefined,
     515                 :                     "PQsetClientEncoding(%s) failed.\n%s", 
     516               0 :                     encoding, PQerrorMessage( hPGConn ) );
     517                 :         }
     518                 :     }
     519                 : 
     520                 : /* -------------------------------------------------------------------- */
     521                 : /*      Install a notice processor.                                     */
     522                 : /* -------------------------------------------------------------------- */
     523             114 :     PQsetNoticeProcessor( hPGConn, OGRPGNoticeProcessor, this );
     524                 : 
     525                 : /* -------------------------------------------------------------------- */
     526                 : /*      Try to establish the database name from the connection          */
     527                 : /*      string passed.                                                  */
     528                 : /* -------------------------------------------------------------------- */
     529             114 :     if( strstr(pszNewName, "dbname=") != NULL )
     530                 :     {
     531             114 :         pszDBName = CPLStrdup( strstr(pszNewName, "dbname=") + 7 );
     532                 : 
     533            1026 :         for( int i = 0; pszDBName[i] != '\0'; i++ )
     534                 :         {
     535             923 :             if( pszDBName[i] == ' ' )
     536                 :             {
     537              11 :                 pszDBName[i] = '\0';
     538              11 :                 break;
     539                 :             }
     540                 :         }
     541                 :     }
     542               0 :     else if( getenv( "USER" ) != NULL )
     543               0 :         pszDBName = CPLStrdup( getenv("USER") );
     544                 :     else
     545               0 :         pszDBName = CPLStrdup( "unknown_dbname" );
     546                 : 
     547             114 :     CPLDebug( "PG", "DBName=\"%s\"", pszDBName );
     548                 : 
     549                 : /* -------------------------------------------------------------------- */
     550                 : /*      Set active schema if different from 'public'                    */
     551                 : /* -------------------------------------------------------------------- */
     552             114 :     if (strcmp(osActiveSchema, "public") != 0)
     553                 :     {
     554               4 :         CPLString osCommand;
     555               4 :         osCommand.Printf("SET search_path='%s',public", osActiveSchema.c_str());
     556               4 :         PGresult    *hResult = OGRPG_PQexec(hPGConn, osCommand );
     557                 : 
     558               4 :         if( !hResult || PQresultStatus(hResult) != PGRES_COMMAND_OK )
     559                 :         {
     560               0 :             OGRPGClearResult( hResult );
     561               0 :             CPLDebug("PG","Command \"%s\" failed. Trying without 'public'.",osCommand.c_str());
     562               0 :             osCommand.Printf("SET search_path='%s'", osActiveSchema.c_str());
     563               0 :             PGresult    *hResult2 = OGRPG_PQexec(hPGConn, osCommand );
     564                 : 
     565               0 :             if( !hResult2 || PQresultStatus(hResult2) != PGRES_COMMAND_OK )
     566                 :             {
     567               0 :                 OGRPGClearResult( hResult2 );
     568                 : 
     569                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     570               0 :                         "%s", PQerrorMessage(hPGConn) );
     571                 : 
     572                 :                 goto end;
     573                 :             }
     574                 :         }
     575                 : 
     576               4 :         OGRPGClearResult(hResult);
     577                 :     }
     578                 : 
     579                 : /* -------------------------------------------------------------------- */
     580                 : /*      Find out PostgreSQL version                                     */
     581                 : /* -------------------------------------------------------------------- */
     582             114 :     sPostgreSQLVersion.nMajor = -1;
     583             114 :     sPostgreSQLVersion.nMinor = -1;
     584             114 :     sPostgreSQLVersion.nRelease = -1;
     585                 : 
     586             114 :     hResult = OGRPG_PQexec(hPGConn, "SELECT version()" );
     587             114 :     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
     588                 :         && PQntuples(hResult) > 0 )
     589                 :     {
     590             114 :         char * pszVer = PQgetvalue(hResult,0,0);
     591                 : 
     592             114 :         CPLDebug("PG","PostgreSQL version string : '%s'", pszVer);
     593                 : 
     594             114 :         if (EQUALN(pszVer, "PostgreSQL ", 11))
     595                 :         {
     596             114 :             OGRPGDecodeVersionString(&sPostgreSQLVersion, pszVer + 11);
     597             114 :             if (sPostgreSQLVersion.nMajor == 7 && sPostgreSQLVersion.nMinor < 4)
     598                 :             {
     599                 :                 /* We don't support BINARY CURSOR for PostgreSQL < 7.4. */
     600                 :                 /* The binary protocol for arrays seems to be different from later versions */
     601               0 :                 CPLDebug("PG","BINARY cursor will finally NOT be used because version < 7.4");
     602               0 :                 bUseBinaryCursor = FALSE;
     603                 :             }
     604                 :         }
     605                 :     }
     606             114 :     OGRPGClearResult(hResult);
     607             114 :     CPLAssert(NULL == hResult); /* Test if safe PQclear has not been broken */
     608                 : 
     609                 : /* -------------------------------------------------------------------- */
     610                 : /*      Test if standard_conforming_strings is recognized               */
     611                 : /* -------------------------------------------------------------------- */
     612                 : 
     613             114 :     hResult = OGRPG_PQexec(hPGConn, "SHOW standard_conforming_strings" );
     614             114 :     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
     615                 :         && PQntuples(hResult) == 1 )
     616                 :     {
     617                 :         /* Whatever the value is, it means that we can use the E'' */
     618                 :         /* syntax */
     619             114 :         bUseEscapeStringSyntax = TRUE;
     620                 :     }
     621             114 :     OGRPGClearResult(hResult);
     622                 : 
     623                 : /* -------------------------------------------------------------------- */
     624                 : /*      Test if time binary format is int8 or float8                    */
     625                 : /* -------------------------------------------------------------------- */
     626                 : #if !defined(PG_PRE74)
     627             114 :     if (bUseBinaryCursor)
     628                 :     {
     629               4 :         SoftStartTransaction();
     630                 : 
     631               4 :         hResult = OGRPG_PQexec(hPGConn, "DECLARE gettimebinaryformat BINARY CURSOR FOR SELECT CAST ('00:00:01' AS time)");
     632                 : 
     633               4 :         if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
     634                 :         {
     635               4 :             OGRPGClearResult( hResult );
     636                 : 
     637               4 :             hResult = OGRPG_PQexec(hPGConn, "FETCH ALL IN gettimebinaryformat" );
     638                 : 
     639               4 :             if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK  && PQntuples(hResult) == 1 )
     640                 :             {
     641               4 :                 if ( PQfformat( hResult, 0 ) == 1 ) // Binary data representation
     642                 :                 {
     643               0 :                     CPLAssert(PQgetlength(hResult, 0, 0) == 8);
     644                 :                     double dVal;
     645                 :                     unsigned int nVal[2];
     646               0 :                     memcpy( nVal, PQgetvalue( hResult, 0, 0 ), 8 );
     647               0 :                     CPL_MSBPTR32(&nVal[0]);
     648               0 :                     CPL_MSBPTR32(&nVal[1]);
     649               0 :                     memcpy( &dVal, PQgetvalue( hResult, 0, 0 ), 8 );
     650               0 :                     CPL_MSBPTR64(&dVal);
     651               0 :                     if (nVal[0] == 0 && nVal[1] == 1000000)
     652                 :                     {
     653               0 :                         bBinaryTimeFormatIsInt8 = TRUE;
     654               0 :                         CPLDebug( "PG", "Time binary format is int8");
     655                 :                     }
     656               0 :                     else if (dVal == 1.)
     657                 :                     {
     658               0 :                         bBinaryTimeFormatIsInt8 = FALSE;
     659               0 :                         CPLDebug( "PG", "Time binary format is float8");
     660                 :                     }
     661                 :                     else
     662                 :                     {
     663               0 :                         bBinaryTimeFormatIsInt8 = FALSE;
     664               0 :                         CPLDebug( "PG", "Time binary format is unknown");
     665                 :                     }
     666                 :                 }
     667                 :             }
     668                 :         }
     669                 : 
     670               4 :         OGRPGClearResult( hResult );
     671                 : 
     672               4 :         hResult = OGRPG_PQexec(hPGConn, "CLOSE gettimebinaryformat");
     673               4 :         OGRPGClearResult( hResult );
     674                 : 
     675               4 :         SoftCommit();
     676                 :     }
     677                 : #endif
     678                 : 
     679                 : #ifdef notdef
     680                 :     /* This would be the quickest fix... instead, ogrpglayer has been updated to support */
     681                 :     /* bytea hex format */
     682                 :     if (sPostgreSQLVersion.nMajor >= 9)
     683                 :     {
     684                 :         /* Starting with PostgreSQL 9.0, the default output format for values of type bytea */
     685                 :         /* is hex, whereas we traditionnaly expect escape */
     686                 :         hResult = OGRPG_PQexec(hPGConn, "SET bytea_output TO escape");
     687                 :         OGRPGClearResult( hResult );
     688                 :     }
     689                 : #endif
     690                 : 
     691                 : /* -------------------------------------------------------------------- */
     692                 : /*      Test to see if this database instance has support for the       */
     693                 : /*      PostGIS Geometry type.  If so, disable sequential scanning      */
     694                 : /*      so we will get the value of the gist indexes.                   */
     695                 : /* -------------------------------------------------------------------- */
     696             114 :     hResult = OGRPG_PQexec(hPGConn, "BEGIN");
     697                 : 
     698             114 :     if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
     699                 :     {
     700             114 :         OGRPGClearResult( hResult );
     701             114 :         CPLAssert(NULL == hResult);
     702                 : 
     703                 :         hResult = OGRPG_PQexec(hPGConn,
     704             114 :                          "SELECT oid FROM pg_type WHERE typname = 'geometry'" );
     705                 :     }
     706                 : 
     707             114 :     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
     708                 :         && PQntuples(hResult) > 0  && CSLTestBoolean(CPLGetConfigOption("PG_USE_POSTGIS", "YES")))
     709                 :     {
     710              81 :         bHavePostGIS = TRUE;
     711              81 :         nGeometryOID = atoi(PQgetvalue(hResult,0,0));
     712                 :     }
     713                 :     else
     714                 :     {
     715              33 :         nGeometryOID = (Oid) 0;
     716                 :     }
     717                 : 
     718             114 :     OGRPGClearResult( hResult );
     719                 : 
     720                 : /* -------------------------------------------------------------------- */
     721                 : /*      Find out PostGIS version                                        */
     722                 : /* -------------------------------------------------------------------- */
     723                 : 
     724             114 :     sPostGISVersion.nMajor = -1;
     725             114 :     sPostGISVersion.nMinor = -1;
     726             114 :     sPostGISVersion.nRelease = -1;
     727                 : 
     728             114 :     if( bHavePostGIS )
     729                 :     {
     730              81 :         hResult = OGRPG_PQexec(hPGConn, "SELECT postgis_version()" );
     731              81 :         if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
     732                 :             && PQntuples(hResult) > 0 )
     733                 :         {
     734              81 :             char * pszVer = PQgetvalue(hResult,0,0);
     735                 : 
     736              81 :             CPLDebug("PG","PostGIS version string : '%s'", pszVer);
     737                 : 
     738              81 :             OGRPGDecodeVersionString(&sPostGISVersion, pszVer);
     739                 : 
     740                 :         }
     741              81 :         OGRPGClearResult(hResult);
     742                 : 
     743                 : 
     744              81 :         if (sPostGISVersion.nMajor == 0 && sPostGISVersion.nMinor < 8)
     745                 :         {
     746                 :             // Turning off sequential scans for PostGIS < 0.8
     747               0 :             hResult = OGRPG_PQexec(hPGConn, "SET ENABLE_SEQSCAN = OFF");
     748                 :             
     749               0 :             CPLDebug( "PG", "SET ENABLE_SEQSCAN=OFF" );
     750                 :         }
     751                 :         else
     752                 :         {
     753                 :             // PostGIS >=0.8 is correctly integrated with query planner,
     754                 :             // thus PostgreSQL will use indexes whenever appropriate.
     755              81 :             hResult = OGRPG_PQexec(hPGConn, "SET ENABLE_SEQSCAN = ON");
     756                 :         }
     757              81 :         OGRPGClearResult( hResult );
     758                 :     }
     759                 : 
     760                 : /* -------------------------------------------------------------------- */
     761                 : /*      Find out "unknown SRID" value                                   */
     762                 : /* -------------------------------------------------------------------- */
     763                 : 
     764             114 :     if (sPostGISVersion.nMajor >= 2)
     765                 :     {
     766                 :         hResult = OGRPG_PQexec(hPGConn,
     767               0 :                         "SELECT ST_Srid('POINT EMPTY'::GEOMETRY)" );
     768                 : 
     769               0 :         if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
     770                 :             && PQntuples(hResult) > 0)
     771                 :         {
     772               0 :             nUndefinedSRID = atoi(PQgetvalue(hResult,0,0));
     773                 :         }
     774                 : 
     775               0 :         OGRPGClearResult( hResult );
     776                 :     }
     777                 :     else
     778             114 :         nUndefinedSRID = -1;
     779                 : 
     780             114 :     hResult = OGRPG_PQexec(hPGConn, "COMMIT");
     781             114 :     OGRPGClearResult( hResult );
     782                 : 
     783                 : /* -------------------------------------------------------------------- */
     784                 : /*      Get a list of available tables if they have not been            */
     785                 : /*      specified through the TABLES connection string param           */
     786                 : /* -------------------------------------------------------------------- */
     787                 : 
     788             114 :     hSetTables = CPLHashSetNew(OGRPGHashTableEntry, OGRPGEqualTableEntry, OGRPGFreeTableEntry);
     789                 : 
     790             114 :     if (nTableCount == 0)
     791                 :     {
     792             109 :         CPLString osCommand;
     793                 :         const char* pszAllowedRelations;
     794             109 :         if( CSLTestBoolean(CPLGetConfigOption("PG_SKIP_VIEWS", "NO")) )
     795               0 :             pszAllowedRelations = "'r'";
     796                 :         else
     797             109 :             pszAllowedRelations = "'r','v'";
     798                 :         
     799             109 :         hResult = OGRPG_PQexec(hPGConn, "BEGIN");
     800                 : 
     801             109 :         if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
     802                 :         {
     803             109 :             OGRPGClearResult( hResult );
     804                 : 
     805                 :             /* Caution : in PostGIS case, the result has 3 columns, whereas in the */
     806                 :             /* non-PostGIS case it has only 2 columns */
     807             186 :             if ( bHavePostGIS && !bListAllTables )
     808                 :             {
     809                 :                 /* PostGIS 1.5 brings support for 'geography' type. */
     810                 :                 /* Checks that the type exists */
     811                 : 
     812                 :                 /* Note: the PG_USE_GEOGRAPHY config option is only used for testing */
     813                 :                 /* purpose, to test the ability of the driver to work with older PostGIS */
     814                 :                 /* versions, even when we have a newer one. It should not be used by */
     815                 :                 /* *real* OGR users */
     816              77 :                 if ((sPostGISVersion.nMajor > 1 ||
     817                 :                     (sPostGISVersion.nMajor == 1 && sPostGISVersion.nMinor >= 5)) &&
     818                 :                     CSLTestBoolean(CPLGetConfigOption("PG_USE_GEOGRAPHY", "YES")) )
     819                 :                 {
     820                 :                     hResult = OGRPG_PQexec(hPGConn,
     821              77 :                                     "SELECT oid FROM pg_type WHERE typname = 'geography'" );
     822                 : 
     823              77 :                     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
     824                 :                         && PQntuples(hResult) > 0)
     825                 :                     {
     826              77 :                         bHaveGeography = TRUE;
     827              77 :                         nGeographyOID = atoi(PQgetvalue(hResult,0,0));
     828                 :                     }
     829                 :                     else
     830                 :                     {
     831               0 :                         CPLDebug("PG", "PostGIS >= 1.5 detected but cannot find 'geography' type");
     832                 :                     }
     833                 :                     
     834              77 :                     OGRPGClearResult( hResult );
     835                 :                 }
     836                 :                 
     837                 :                 osCommand.Printf("DECLARE mycursor CURSOR for "
     838                 :                                  "SELECT c.relname, n.nspname, g.f_geometry_column, g.type, g.coord_dimension, g.srid, %d FROM pg_class c, pg_namespace n, geometry_columns g "
     839                 :                                  "WHERE (c.relkind in (%s) AND c.relname !~ '^pg_' AND c.relnamespace=n.oid "
     840                 :                                  "AND c.relname::TEXT = g.f_table_name::TEXT AND n.nspname = g.f_table_schema)",
     841              77 :                                  GEOM_TYPE_GEOMETRY, pszAllowedRelations);
     842                 : 
     843              77 :                 if (bHaveGeography)
     844                 :                     osCommand += CPLString().Printf(
     845                 :                                      "UNION SELECT c.relname, n.nspname, g.f_geography_column, g.type, g.coord_dimension, g.srid, %d FROM pg_class c, pg_namespace n, geography_columns g "
     846                 :                                      "WHERE (c.relkind in (%s) AND c.relname !~ '^pg_' AND c.relnamespace=n.oid "
     847                 :                                      "AND c.relname::TEXT = g.f_table_name::TEXT AND n.nspname = g.f_table_schema)",
     848              77 :                                      GEOM_TYPE_GEOGRAPHY, pszAllowedRelations);
     849                 :             }
     850                 :             else
     851                 :                 osCommand.Printf("DECLARE mycursor CURSOR for "
     852                 :                                  "SELECT c.relname, n.nspname FROM pg_class c, pg_namespace n "
     853                 :                                  "WHERE (c.relkind in (%s) AND c.relname !~ '^pg_' AND c.relnamespace=n.oid)",
     854              32 :                                  pszAllowedRelations);
     855                 :                                 
     856             109 :             hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
     857                 :         }
     858                 : 
     859             109 :         if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
     860                 :         {
     861             109 :             OGRPGClearResult( hResult );
     862             109 :             hResult = OGRPG_PQexec(hPGConn, "FETCH ALL in mycursor" );
     863                 :         }
     864                 : 
     865             109 :         if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
     866                 :         {
     867               0 :             OGRPGClearResult( hResult );
     868                 : 
     869                 :             CPLError( CE_Failure, CPLE_AppDefined,
     870               0 :                     "%s", PQerrorMessage(hPGConn) );
     871                 :             goto end;
     872                 :         }
     873                 : 
     874                 :     /* -------------------------------------------------------------------- */
     875                 :     /*      Parse the returned table list                                   */
     876                 :     /* -------------------------------------------------------------------- */
     877           18465 :         for( int iRecord = 0; iRecord < PQntuples(hResult); iRecord++ )
     878                 :         {
     879           18356 :             const char *pszTable = PQgetvalue(hResult, iRecord, 0);
     880           18356 :             const char *pszSchemaName = PQgetvalue(hResult, iRecord, 1);
     881           18356 :             const char *pszGeomColumnName = NULL;
     882           18356 :             const char *pszGeomType = NULL;
     883           18356 :             int nGeomCoordDimension = 0;
     884           18356 :             int nSRID = 0;
     885           18356 :             PostgisType ePostgisType = GEOM_TYPE_UNKNOWN;
     886           18356 :             if (bHavePostGIS && !bListAllTables)
     887                 :             {
     888           11272 :                 pszGeomColumnName = PQgetvalue(hResult, iRecord, 2);
     889           11272 :                 pszGeomType = PQgetvalue(hResult, iRecord, 3);
     890           11272 :                 nGeomCoordDimension = atoi(PQgetvalue(hResult, iRecord, 4));
     891           11272 :                 nSRID = atoi(PQgetvalue(hResult, iRecord, 5));
     892           11272 :                 ePostgisType = (PostgisType) atoi(PQgetvalue(hResult, iRecord, 6));
     893                 :             }
     894                 : 
     895           18356 :             if( EQUAL(pszTable,"spatial_ref_sys")
     896                 :                 || EQUAL(pszTable,"geometry_columns")
     897                 :                 || EQUAL(pszTable,"geography_columns") )
     898              96 :                 continue;
     899                 : 
     900           18260 :             if( EQUAL(pszSchemaName,"information_schema") )
     901            1760 :                 continue;
     902                 : 
     903           16500 :             papsTables = (PGTableEntry**)CPLRealloc(papsTables, sizeof(PGTableEntry*) * (nTableCount + 1));
     904           16500 :             papsTables[nTableCount] = (PGTableEntry*) CPLCalloc(1, sizeof(PGTableEntry));
     905           16500 :             papsTables[nTableCount]->pszTableName = CPLStrdup( pszTable );
     906           16500 :             papsTables[nTableCount]->pszSchemaName = CPLStrdup( pszSchemaName );
     907           16500 :             if (pszGeomColumnName)
     908                 :                 OGRPGTableEntryAddGeomColumn(papsTables[nTableCount],
     909                 :                                              pszGeomColumnName,
     910                 :                                              pszGeomType, nGeomCoordDimension,
     911           11272 :                                              nSRID, ePostgisType);
     912           16500 :             nTableCount ++;
     913                 : 
     914           16500 :             PGTableEntry* psEntry = OGRPGFindTableEntry(hSetTables, pszTable, pszSchemaName);
     915           16500 :             if (psEntry == NULL)
     916           16443 :                 psEntry = OGRPGAddTableEntry(hSetTables, pszTable, pszSchemaName);
     917           16500 :             if (pszGeomColumnName)
     918                 :                 OGRPGTableEntryAddGeomColumn(psEntry,
     919                 :                                              pszGeomColumnName,
     920                 :                                              pszGeomType,
     921                 :                                              nGeomCoordDimension,
     922           11272 :                                              nSRID, ePostgisType);
     923                 :         }
     924                 : 
     925                 :     /* -------------------------------------------------------------------- */
     926                 :     /*      Cleanup                                                         */
     927                 :     /* -------------------------------------------------------------------- */
     928             109 :         OGRPGClearResult( hResult );
     929                 : 
     930             109 :         hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
     931             109 :         OGRPGClearResult( hResult );
     932                 : 
     933             109 :         hResult = OGRPG_PQexec(hPGConn, "COMMIT");
     934             109 :         OGRPGClearResult( hResult );
     935                 : 
     936             109 :         if ( bHavePostGIS && !bListAllTables )
     937                 :         {
     938              77 :             hResult = OGRPG_PQexec(hPGConn, "BEGIN");
     939                 : 
     940              77 :             OGRPGClearResult( hResult );
     941                 : 
     942                 :         /* -------------------------------------------------------------------- */
     943                 :         /*      Fetch inherited tables                                          */
     944                 :         /* -------------------------------------------------------------------- */
     945                 :             hResult = OGRPG_PQexec(hPGConn,
     946                 :                                 "DECLARE mycursor CURSOR for "
     947                 :                                 "SELECT c1.relname AS derived, c2.relname AS parent, n.nspname "
     948                 :                                 "FROM pg_class c1, pg_class c2, pg_namespace n, pg_inherits i "
     949                 :                                 "WHERE i.inhparent = c2.oid AND i.inhrelid = c1.oid AND c1.relnamespace=n.oid "
     950                 :                                 "AND c1.relkind in ('r', 'v') AND c1.relnamespace=n.oid AND c2.relkind in ('r','v') "
     951              77 :                                 "AND c2.relname !~ '^pg_' AND c2.relnamespace=n.oid");
     952                 : 
     953              77 :             if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
     954                 :             {
     955              77 :                 OGRPGClearResult( hResult );
     956              77 :                 hResult = OGRPG_PQexec(hPGConn, "FETCH ALL in mycursor" );
     957                 :             }
     958                 : 
     959              77 :             if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
     960                 :             {
     961               0 :                 OGRPGClearResult( hResult );
     962                 : 
     963                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     964               0 :                         "%s", PQerrorMessage(hPGConn) );
     965                 :                 goto end;
     966                 :             }
     967                 : 
     968                 :         /* -------------------------------------------------------------------- */
     969                 :         /*      Parse the returned table list                                   */
     970                 :         /* -------------------------------------------------------------------- */
     971                 :             int bHasDoneSomething;
     972             139 :             do
     973                 :             {
     974                 :                 /* Iterate over the tuples while we have managed to resolved at least one */
     975                 :                 /* table to its table parent with a geometry */
     976                 :                 /* For example if we have C inherits B and B inherits A, where A is a base table with a geometry */
     977                 :                 /* The first pass will add B to the set of tables */
     978                 :                 /* The second pass will add C to the set of tables */
     979                 : 
     980             139 :                 bHasDoneSomething = FALSE;
     981                 : 
     982             621 :                 for( int iRecord = 0; iRecord < PQntuples(hResult); iRecord++ )
     983                 :                 {
     984             482 :                     const char *pszTable = PQgetvalue(hResult, iRecord, 0);
     985             482 :                     const char *pszParentTable = PQgetvalue(hResult, iRecord, 1);
     986             482 :                     const char *pszSchemaName = PQgetvalue(hResult, iRecord, 2);
     987                 : 
     988             482 :                     PGTableEntry* psEntry = OGRPGFindTableEntry(hSetTables, pszTable, pszSchemaName);
     989                 :                     /* We must be careful that a derived table can have its own geometry column(s) */
     990                 :                     /* and some inherited from another table */
     991             482 :                     if (psEntry == NULL || psEntry->bDerivedInfoAdded == FALSE)
     992                 :                     {
     993                 :                         PGTableEntry* psParentEntry =
     994             205 :                                 OGRPGFindTableEntry(hSetTables, pszParentTable, pszSchemaName);
     995             205 :                         if (psParentEntry != NULL)
     996                 :                         {
     997                 :                             /* The parent table of this table is already in the set, so we */
     998                 :                             /* can now add the table in the set if it was not in it already */
     999                 : 
    1000             154 :                             bHasDoneSomething = TRUE;
    1001                 : 
    1002             154 :                             if (psEntry == NULL)
    1003             124 :                                 psEntry = OGRPGAddTableEntry(hSetTables, pszTable, pszSchemaName);
    1004                 : 
    1005                 :                             int iGeomColumn;
    1006             308 :                             for(iGeomColumn = 0; iGeomColumn < psParentEntry->nGeomColumnCount; iGeomColumn++)
    1007                 :                             {
    1008             154 :                                 papsTables = (PGTableEntry**)CPLRealloc(papsTables, sizeof(PGTableEntry*) * (nTableCount + 1));
    1009             154 :                                 papsTables[nTableCount] = (PGTableEntry*) CPLCalloc(1, sizeof(PGTableEntry));
    1010             154 :                                 papsTables[nTableCount]->pszTableName = CPLStrdup( pszTable );
    1011             154 :                                 papsTables[nTableCount]->pszSchemaName = CPLStrdup( pszSchemaName );
    1012                 :                                 OGRPGTableEntryAddGeomColumn(papsTables[nTableCount],
    1013             154 :                                                              &psParentEntry->pasGeomColumns[iGeomColumn]);
    1014             154 :                                 nTableCount ++;
    1015                 : 
    1016                 :                                 OGRPGTableEntryAddGeomColumn(psEntry,
    1017             154 :                                                              &psParentEntry->pasGeomColumns[iGeomColumn]);
    1018                 :                             }
    1019                 : 
    1020             154 :                             psEntry->bDerivedInfoAdded = TRUE;
    1021                 :                         }
    1022                 :                     }
    1023                 :                 }
    1024                 :             } while(bHasDoneSomething);
    1025                 : 
    1026                 :         /* -------------------------------------------------------------------- */
    1027                 :         /*      Cleanup                                                         */
    1028                 :         /* -------------------------------------------------------------------- */
    1029              77 :             OGRPGClearResult( hResult );
    1030                 : 
    1031              77 :             hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
    1032              77 :             OGRPGClearResult( hResult );
    1033                 : 
    1034              77 :             hResult = OGRPG_PQexec(hPGConn, "COMMIT");
    1035              77 :             OGRPGClearResult( hResult );
    1036                 : 
    1037               0 :         }
    1038                 : 
    1039                 :     }
    1040                 : 
    1041             114 :     osCurrentSchema = GetCurrentSchema();
    1042                 : 
    1043                 : /* -------------------------------------------------------------------- */
    1044                 : /*      Register the available tables.                                  */
    1045                 : /* -------------------------------------------------------------------- */
    1046           16775 :     for( int iRecord = 0; iRecord < nTableCount; iRecord++ )
    1047                 :     {
    1048                 :         PGTableEntry* psEntry;
    1049           16661 :         psEntry = (PGTableEntry* )CPLHashSetLookup(hSetTables, papsTables[iRecord]);
    1050                 : 
    1051                 :         /* If SCHEMAS= is specified, only take into account tables inside */
    1052                 :         /* one of the specified schemas */
    1053           17311 :         if (papszSchemaList != NULL &&
    1054             650 :             CSLFindString(papszSchemaList, papsTables[iRecord]->pszSchemaName) == -1)
    1055                 :         {
    1056             508 :             continue;
    1057                 :         }
    1058                 : 
    1059                 :         /* Some heuristics to preserve backward compatibility with the way that */
    1060                 :         /* layers were reported in GDAL <= 1.5.0 */
    1061                 :         /* That is to say : */
    1062                 :         /* - if we get only one geometry column from the request to geometry_columns */
    1063                 :         /*   then use it but don't report it into layer definition */
    1064                 :         /* - if we get several geometry columns, use their names and report them */
    1065                 :         /*   except for the wkb_geometry column */
    1066                 :         /* - if we get no geometry column, let ReadTableDefinition() parses the columns */
    1067                 :         /*   and find the likely geometry column */
    1068                 : 
    1069                 :         OGRPGTableLayer* poLayer;
    1070           32160 :         if (psEntry != NULL && psEntry->nGeomColumnCount <= 1)
    1071                 :         {
    1072           16007 :             if (psEntry->nGeomColumnCount == 1)
    1073                 :             {
    1074           11036 :                 poLayer = OpenTable( osCurrentSchema, papsTables[iRecord]->pszTableName,
    1075           11036 :                            papsTables[iRecord]->pszSchemaName,
    1076           33108 :                            psEntry->pasGeomColumns[0].pszName, bUpdate, FALSE, FALSE );
    1077           11036 :                 poLayer->SetGeometryInformation(psEntry->pasGeomColumns[0].pszGeomType,
    1078           11036 :                                                 psEntry->pasGeomColumns[0].nCoordDimension,
    1079           11036 :                                                 psEntry->pasGeomColumns[0].nSRID,
    1080           44144 :                                                 psEntry->pasGeomColumns[0].ePostgisType);
    1081                 :             }
    1082                 :             else
    1083            4971 :                 poLayer = OpenTable( osCurrentSchema, papsTables[iRecord]->pszTableName,
    1084            9942 :                            papsTables[iRecord]->pszSchemaName, NULL, bUpdate, FALSE, FALSE );
    1085                 :         }
    1086                 :         else
    1087                 :         {
    1088             146 :             if (papsTables[iRecord]->nGeomColumnCount == 0)
    1089               6 :                 poLayer = OpenTable( osCurrentSchema, papsTables[iRecord]->pszTableName,
    1090              12 :                            papsTables[iRecord]->pszSchemaName, NULL, bUpdate, FALSE, FALSE );
    1091                 :             else
    1092                 :             {
    1093             140 :                 poLayer = OpenTable( osCurrentSchema, papsTables[iRecord]->pszTableName,
    1094             280 :                            papsTables[iRecord]->pszSchemaName, papsTables[iRecord]->pasGeomColumns[0].pszName,
    1095             560 :                            bUpdate, FALSE, !EQUAL(papsTables[iRecord]->pasGeomColumns[0].pszName, "wkb_geometry") );
    1096             140 :                 poLayer->SetGeometryInformation(papsTables[iRecord]->pasGeomColumns[0].pszGeomType,
    1097             140 :                                                 papsTables[iRecord]->pasGeomColumns[0].nCoordDimension,
    1098             140 :                                                 papsTables[iRecord]->pasGeomColumns[0].nSRID,
    1099             560 :                                                 papsTables[iRecord]->pasGeomColumns[0].ePostgisType);
    1100                 :             }
    1101                 :         }
    1102                 :     }
    1103                 : 
    1104             114 :     bRet = TRUE;
    1105                 : 
    1106                 : end:
    1107             114 :     if (hSetTables)
    1108             114 :         CPLHashSetDestroy(hSetTables);
    1109             114 :     CSLDestroy( papszSchemaList );
    1110                 : 
    1111           16775 :     for(int i=0;i<nTableCount;i++)
    1112           16661 :         OGRPGFreeTableEntry(papsTables[i]);
    1113             114 :     CPLFree(papsTables);
    1114                 : 
    1115             114 :     return bRet;
    1116                 : }
    1117                 : 
    1118                 : /************************************************************************/
    1119                 : /*                             OpenTable()                              */
    1120                 : /************************************************************************/
    1121                 : 
    1122           16240 : OGRPGTableLayer* OGRPGDataSource::OpenTable( CPLString& osCurrentSchema,
    1123                 :                                 const char *pszNewName,
    1124                 :                                 const char *pszSchemaName,
    1125                 :                                 const char * pszGeomColumnIn,
    1126                 :                                 int bUpdate,
    1127                 :                                 int bTestOpen,
    1128                 :                                 int bAdvertizeGeomColumn)
    1129                 : 
    1130                 : {
    1131                 : /* -------------------------------------------------------------------- */
    1132                 : /*      Create the layer object.                                        */
    1133                 : /* -------------------------------------------------------------------- */
    1134                 :     OGRPGTableLayer  *poLayer;
    1135                 : 
    1136                 :     poLayer = new OGRPGTableLayer( this, osCurrentSchema,
    1137                 :                                    pszNewName, pszSchemaName,
    1138                 :                                    pszGeomColumnIn, bUpdate,
    1139           16240 :                                    bAdvertizeGeomColumn );
    1140           16327 :     if( bTestOpen && poLayer->GetLayerDefnCanReturnNULL() == NULL )
    1141                 :     {
    1142              61 :         delete poLayer;
    1143              61 :         return NULL;
    1144                 :     }
    1145                 : 
    1146                 : /* -------------------------------------------------------------------- */
    1147                 : /*      Add layer to data source layer list.                            */
    1148                 : /* -------------------------------------------------------------------- */
    1149                 :     papoLayers = (OGRPGTableLayer **)
    1150           16179 :         CPLRealloc( papoLayers,  sizeof(OGRPGTableLayer *) * (nLayers+1) );
    1151           16179 :     papoLayers[nLayers++] = poLayer;
    1152                 : 
    1153           16179 :     return poLayer;
    1154                 : }
    1155                 : 
    1156                 : /************************************************************************/
    1157                 : /*                            DeleteLayer()                             */
    1158                 : /************************************************************************/
    1159                 : 
    1160              71 : int OGRPGDataSource::DeleteLayer( int iLayer )
    1161                 : 
    1162                 : {
    1163              71 :     if( iLayer < 0 || iLayer >= nLayers )
    1164               0 :         return OGRERR_FAILURE;
    1165                 : 
    1166                 : /* -------------------------------------------------------------------- */
    1167                 : /*      Blow away our OGR structures related to the layer.  This is     */
    1168                 : /*      pretty dangerous if anything has a reference to this layer!     */
    1169                 : /* -------------------------------------------------------------------- */
    1170              71 :     CPLString osLayerName = papoLayers[iLayer]->GetLayerDefn()->GetName();
    1171              71 :     CPLString osTableName = papoLayers[iLayer]->GetTableName();
    1172              71 :     CPLString osSchemaName = papoLayers[iLayer]->GetSchemaName();
    1173                 : 
    1174              71 :     CPLDebug( "PG", "DeleteLayer(%s)", osLayerName.c_str() );
    1175                 : 
    1176              71 :     delete papoLayers[iLayer];
    1177                 :     memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
    1178              71 :              sizeof(void *) * (nLayers - iLayer - 1) );
    1179              71 :     nLayers--;
    1180                 : 
    1181              71 :     if (osLayerName.size() == 0)
    1182               0 :         return OGRERR_NONE;
    1183                 : 
    1184                 : /* -------------------------------------------------------------------- */
    1185                 : /*      Remove from the database.                                       */
    1186                 : /* -------------------------------------------------------------------- */
    1187                 :     PGresult            *hResult;
    1188              71 :     CPLString            osCommand;
    1189                 : 
    1190              71 :     hResult = OGRPG_PQexec(hPGConn, "BEGIN");
    1191              71 :     OGRPGClearResult( hResult );
    1192                 : 
    1193              71 :     if( bHavePostGIS )
    1194                 :     {
    1195                 :         /* This is unnecessary if the layer is not a geometry table, or an inherited geometry table */
    1196                 :         /* but it shouldn't hurt */
    1197                 :         osCommand.Printf(
    1198                 :                  "SELECT DropGeometryColumn('%s','%s',(SELECT f_geometry_column from geometry_columns where f_table_name='%s' and f_table_schema='%s' order by f_geometry_column limit 1))",
    1199              40 :                  osSchemaName.c_str(), osTableName.c_str(), osTableName.c_str(), osSchemaName.c_str() );
    1200                 : 
    1201              40 :         hResult = OGRPG_PQexec( hPGConn, osCommand.c_str() );
    1202              40 :         OGRPGClearResult( hResult );
    1203                 :     }
    1204                 : 
    1205              71 :     osCommand.Printf("DROP TABLE \"%s\".\"%s\" CASCADE", osSchemaName.c_str(), osTableName.c_str() );
    1206              71 :     hResult = OGRPG_PQexec( hPGConn, osCommand.c_str() );
    1207              71 :     OGRPGClearResult( hResult );
    1208                 : 
    1209              71 :     hResult = OGRPG_PQexec(hPGConn, "COMMIT");
    1210              71 :     OGRPGClearResult( hResult );
    1211                 : 
    1212              71 :     return OGRERR_NONE;
    1213                 : }
    1214                 : 
    1215                 : /************************************************************************/
    1216                 : /*                            CreateLayer()                             */
    1217                 : /************************************************************************/
    1218                 : 
    1219                 : OGRLayer *
    1220              58 : OGRPGDataSource::CreateLayer( const char * pszLayerName,
    1221                 :                               OGRSpatialReference *poSRS,
    1222                 :                               OGRwkbGeometryType eType,
    1223                 :                               char ** papszOptions )
    1224                 : 
    1225                 : {
    1226              58 :     PGresult            *hResult = NULL;
    1227              58 :     CPLString            osCommand;
    1228              58 :     const char          *pszGeomType = NULL;
    1229              58 :     char                *pszTableName = NULL;
    1230              58 :     char                *pszSchemaName = NULL;
    1231              58 :     int                 nDimension = 3;
    1232                 : 
    1233              58 :     if (pszLayerName == NULL)
    1234               0 :         return NULL;
    1235                 : 
    1236              58 :     const char* pszFIDColumnName = CSLFetchNameValue(papszOptions, "FID");
    1237              58 :     CPLString osFIDColumnName;
    1238              58 :     if (pszFIDColumnName == NULL)
    1239              58 :         osFIDColumnName = "OGC_FID";
    1240                 :     else
    1241                 :     {
    1242               0 :         if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
    1243                 :         {
    1244               0 :             char* pszLaunderedFid = LaunderName(pszFIDColumnName);
    1245               0 :             osFIDColumnName += OGRPGEscapeColumnName(pszLaunderedFid);
    1246               0 :             CPLFree(pszLaunderedFid);
    1247                 :         }
    1248                 :         else
    1249               0 :             osFIDColumnName += OGRPGEscapeColumnName(pszFIDColumnName);
    1250                 :     }
    1251              58 :     pszFIDColumnName = osFIDColumnName.c_str();
    1252                 : 
    1253              58 :     if (strncmp(pszLayerName, "pg", 2) == 0)
    1254                 :     {
    1255                 :         CPLError(CE_Warning, CPLE_AppDefined,
    1256               0 :                  "The layer name should not begin by 'pg' as it is a reserved prefix");
    1257                 :     }
    1258                 : 
    1259              58 :     if( wkbFlatten(eType) == eType )
    1260              58 :         nDimension = 2;
    1261                 : 
    1262              58 :     if( CSLFetchNameValue( papszOptions, "DIM") != NULL )
    1263               9 :         nDimension = atoi(CSLFetchNameValue( papszOptions, "DIM"));
    1264                 : 
    1265                 :     /* Should we turn layers with None geometry type as Unknown/GEOMETRY */
    1266                 :     /* so they are still recorded in geometry_columns table ? (#4012) */
    1267                 :     int bNoneAsUnknown = CSLTestBoolean(CSLFetchNameValueDef(
    1268              58 :                                     papszOptions, "NONE_AS_UNKNOWN", "NO"));
    1269              58 :     if (bNoneAsUnknown && eType == wkbNone)
    1270               0 :         eType = wkbUnknown;
    1271                 : 
    1272                 : 
    1273                 :     int bExtractSchemaFromLayerName = CSLTestBoolean(CSLFetchNameValueDef(
    1274              58 :                                     papszOptions, "EXTRACT_SCHEMA_FROM_LAYER_NAME", "YES"));
    1275                 : 
    1276                 :     /* Postgres Schema handling:
    1277                 :        Extract schema name from input layer name or passed with -lco SCHEMA.
    1278                 :        Set layer name to "schema.table" or to "table" if schema == current_schema()
    1279                 :        Usage without schema name is backwards compatible
    1280                 :     */
    1281              58 :     const char* pszDotPos = strstr(pszLayerName,".");
    1282              61 :     if ( pszDotPos != NULL && bExtractSchemaFromLayerName )
    1283                 :     {
    1284               3 :       int length = pszDotPos - pszLayerName;
    1285               3 :       pszSchemaName = (char*)CPLMalloc(length+1);
    1286               3 :       strncpy(pszSchemaName, pszLayerName, length);
    1287               3 :       pszSchemaName[length] = '\0';
    1288                 :       
    1289               3 :       if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
    1290               3 :           pszTableName = LaunderName( pszDotPos + 1 ); //skip "."
    1291                 :       else
    1292               0 :           pszTableName = CPLStrdup( pszDotPos + 1 ); //skip "."
    1293                 :     }
    1294                 :     else
    1295                 :     {
    1296              55 :       pszSchemaName = NULL;
    1297              55 :       if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
    1298              55 :           pszTableName = LaunderName( pszLayerName ); //skip "."
    1299                 :       else
    1300               0 :           pszTableName = CPLStrdup( pszLayerName ); //skip "."
    1301                 :     }
    1302                 : 
    1303                 : /* -------------------------------------------------------------------- */
    1304                 : /*      Set the default schema for the layers.                          */
    1305                 : /* -------------------------------------------------------------------- */
    1306              58 :     if( CSLFetchNameValue( papszOptions, "SCHEMA" ) != NULL )
    1307                 :     {
    1308               3 :         CPLFree(pszSchemaName);
    1309               3 :         pszSchemaName = CPLStrdup(CSLFetchNameValue( papszOptions, "SCHEMA" ));
    1310                 :     }
    1311                 : 
    1312              58 :     if ( pszSchemaName == NULL && strlen(osCurrentSchema) > 0)
    1313                 :     {
    1314              54 :       pszSchemaName = CPLStrdup(osCurrentSchema);
    1315                 :     }
    1316                 : 
    1317                 : /* -------------------------------------------------------------------- */
    1318                 : /*      Do we already have this layer?  If so, should we blow it        */
    1319                 : /*      away?                                                           */
    1320                 : /* -------------------------------------------------------------------- */
    1321                 :     int iLayer;
    1322                 : 
    1323              58 :     FlushSoftTransaction();
    1324                 : 
    1325              58 :     CPLString osSQLLayerName;
    1326              58 :     if (pszSchemaName == NULL || (strlen(osCurrentSchema) > 0 && EQUAL(pszSchemaName, osCurrentSchema.c_str())))
    1327              54 :         osSQLLayerName = pszTableName;
    1328                 :     else
    1329                 :     {
    1330               4 :         osSQLLayerName = pszSchemaName;
    1331               4 :         osSQLLayerName += ".";
    1332               4 :         osSQLLayerName += pszTableName;
    1333                 :     }
    1334                 : 
    1335                 :     /* GetLayerByName() can instanciate layers that would have been */
    1336                 :     /* 'hidden' otherwise, for example, non-spatial tables in a */
    1337                 :     /* Postgis-enabled database, so this apparently useless command is */
    1338                 :     /* not useless... (#4012) */
    1339              58 :     CPLPushErrorHandler(CPLQuietErrorHandler);
    1340              58 :     GetLayerByName(osSQLLayerName);
    1341              58 :     CPLPopErrorHandler();
    1342              58 :     CPLErrorReset();
    1343                 : 
    1344            8862 :     for( iLayer = 0; iLayer < nLayers; iLayer++ )
    1345                 :     {
    1346            8806 :         if( EQUAL(osSQLLayerName.c_str(),papoLayers[iLayer]->GetName()) )
    1347                 :         {
    1348               8 :             if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
    1349                 :                 && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
    1350                 :             {
    1351               6 :                 DeleteLayer( iLayer );
    1352                 :             }
    1353                 :             else
    1354                 :             {
    1355                 :                 CPLError( CE_Failure, CPLE_AppDefined,
    1356                 :                           "Layer %s already exists, CreateLayer failed.\n"
    1357                 :                           "Use the layer creation option OVERWRITE=YES to "
    1358                 :                           "replace it.",
    1359               2 :                           osSQLLayerName.c_str() );
    1360               2 :                 CPLFree( pszTableName );
    1361               2 :                 CPLFree( pszSchemaName );
    1362               2 :                 return NULL;
    1363                 :             }
    1364                 :         }
    1365                 :     }
    1366                 : 
    1367                 : /* -------------------------------------------------------------------- */
    1368                 : /*      Handle the GEOM_TYPE option.                                    */
    1369                 : /* -------------------------------------------------------------------- */
    1370              56 :     pszGeomType = CSLFetchNameValue( papszOptions, "GEOM_TYPE" );
    1371              56 :     if( pszGeomType == NULL )
    1372                 :     {
    1373              55 :         if( bHavePostGIS )
    1374              36 :             pszGeomType = "geometry";
    1375                 :         else
    1376              19 :             pszGeomType = "bytea";
    1377                 :     }
    1378                 :     
    1379              56 :     if( eType != wkbNone && EQUAL(pszGeomType, "geography") && !bHaveGeography )
    1380                 :     {
    1381                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1382                 :                   "GEOM_TYPE=geography is only supported in PostGIS >= 1.5.\n"
    1383                 :                   "Creation of layer %s has failed.",
    1384               0 :                   pszLayerName );
    1385               0 :         CPLFree( pszTableName );
    1386               0 :         CPLFree( pszSchemaName );
    1387               0 :         return NULL;
    1388                 :     }
    1389                 : 
    1390              56 :     if( eType != wkbNone && bHavePostGIS && !EQUAL(pszGeomType,"geometry") &&
    1391                 :         !EQUAL(pszGeomType, "geography") )
    1392                 :     {
    1393               0 :         if( bHaveGeography )
    1394                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1395                 :                       "GEOM_TYPE in PostGIS enabled databases must be 'geometry' or 'geography'.\n"
    1396                 :                       "Creation of layer %s with GEOM_TYPE %s has failed.",
    1397               0 :                       pszLayerName, pszGeomType );
    1398                 :         else
    1399                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1400                 :                       "GEOM_TYPE in PostGIS enabled databases must be 'geometry'.\n"
    1401                 :                       "Creation of layer %s with GEOM_TYPE %s has failed.",
    1402               0 :                       pszLayerName, pszGeomType );
    1403                 : 
    1404               0 :         CPLFree( pszTableName );
    1405               0 :         CPLFree( pszSchemaName );
    1406               0 :         return NULL;
    1407                 :     }
    1408                 : 
    1409                 : /* -------------------------------------------------------------------- */
    1410                 : /*      Try to get the SRS Id of this spatial reference system,         */
    1411                 : /*      adding tot the srs table if needed.                             */
    1412                 : /* -------------------------------------------------------------------- */
    1413              56 :     int nSRSId = nUndefinedSRID;
    1414                 : 
    1415              56 :     if( poSRS != NULL )
    1416              13 :         nSRSId = FetchSRSId( poSRS );
    1417                 :         
    1418              56 :     const char *pszGeometryType = OGRToOGCGeomType(eType);
    1419                 : /* -------------------------------------------------------------------- */
    1420                 : /*      Create a basic table with the FID.  Also include the            */
    1421                 : /*      geometry if this is not a PostGIS enabled table.                */
    1422                 : /* -------------------------------------------------------------------- */
    1423              56 :     hResult = OGRPG_PQexec(hPGConn, "BEGIN");
    1424              56 :     OGRPGClearResult( hResult );
    1425                 :     
    1426              56 :     const char *pszGFldName = NULL;
    1427                 :     
    1428              56 :     CPLString osCreateTable;
    1429                 :     int bTemporary = CSLFetchNameValue( papszOptions, "TEMPORARY" ) != NULL &&
    1430              56 :                      CSLTestBoolean(CSLFetchNameValue( papszOptions, "TEMPORARY" ));
    1431              56 :     if (bTemporary)
    1432                 :     {
    1433               0 :         CPLFree(pszSchemaName);
    1434               0 :         pszSchemaName = CPLStrdup("pg_temp_1");
    1435               0 :         osCreateTable.Printf("CREATE TEMPORARY TABLE \"%s\"", pszTableName);
    1436                 :     }
    1437                 :     else
    1438              56 :         osCreateTable.Printf("CREATE TABLE \"%s\".\"%s\"", pszSchemaName, pszTableName);
    1439                 :     
    1440              72 :     if( eType != wkbNone && !bHavePostGIS )
    1441                 :     {
    1442                 :         osCommand.Printf(
    1443                 :                  "%s ( "
    1444                 :                  "    %s SERIAL, "
    1445                 :                  "   WKB_GEOMETRY %s, "
    1446                 :                  "   CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
    1447                 :                  osCreateTable.c_str(),
    1448                 :                  pszFIDColumnName,
    1449                 :                  pszGeomType,
    1450              16 :                  pszTableName, pszFIDColumnName);
    1451                 :     }
    1452              41 :     else if ( eType != wkbNone && EQUAL(pszGeomType, "geography") )
    1453                 :     {
    1454               1 :         if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
    1455               1 :             pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
    1456                 :         else
    1457               0 :             pszGFldName = "the_geog";
    1458                 :         
    1459               1 :         if (nSRSId)
    1460                 :             osCommand.Printf(
    1461                 :                      "%s ( %s SERIAL, %s geography(%s%s,%d), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
    1462                 :                      osCreateTable.c_str(), pszFIDColumnName,
    1463                 :                      OGRPGEscapeColumnName(pszGFldName).c_str(), pszGeometryType,
    1464                 :                      nDimension == 2 ? "" : "Z", nSRSId, pszTableName,
    1465               1 :                      pszFIDColumnName);
    1466                 :         else
    1467                 :             osCommand.Printf(
    1468                 :                      "%s ( %s SERIAL, %s geography(%s%s), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
    1469                 :                      osCreateTable.c_str(), pszFIDColumnName,
    1470                 :                      OGRPGEscapeColumnName(pszGFldName).c_str(), pszGeometryType,
    1471                 :                      nDimension == 2 ? "" : "Z", pszTableName,
    1472               0 :                      pszFIDColumnName);
    1473                 :     }
    1474                 :     else
    1475                 :     {
    1476                 :         osCommand.Printf(
    1477                 :                  "%s ( %s SERIAL, CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
    1478              39 :                  osCreateTable.c_str(), pszFIDColumnName, pszTableName, pszFIDColumnName );
    1479                 :     }
    1480                 : 
    1481              56 :     hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
    1482              56 :     if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
    1483                 :     {
    1484                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1485               0 :                   "%s\n%s", osCommand.c_str(), PQerrorMessage(hPGConn) );
    1486               0 :         CPLFree( pszTableName );
    1487               0 :         CPLFree( pszSchemaName );
    1488                 : 
    1489               0 :         OGRPGClearResult( hResult );
    1490               0 :         hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
    1491               0 :         OGRPGClearResult( hResult );
    1492               0 :         return NULL;
    1493                 :     }
    1494                 : 
    1495              56 :     OGRPGClearResult( hResult );
    1496                 : 
    1497              56 :     CPLString osEscapedTableNameSingleQuote = OGRPGEscapeString(hPGConn, pszTableName);
    1498              56 :     const char* pszEscapedTableNameSingleQuote = osEscapedTableNameSingleQuote.c_str();
    1499                 : 
    1500                 : /* -------------------------------------------------------------------- */
    1501                 : /*      Eventually we should be adding this table to a table of         */
    1502                 : /*      "geometric layers", capturing the WKT projection, and           */
    1503                 : /*      perhaps some other housekeeping.                                */
    1504                 : /* -------------------------------------------------------------------- */
    1505              56 :     if( eType != wkbNone && bHavePostGIS && !EQUAL(pszGeomType, "geography"))
    1506                 :     {
    1507              31 :         if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
    1508               2 :             pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
    1509                 :         else
    1510              29 :             pszGFldName = "wkb_geometry";
    1511                 : 
    1512              31 :         if (sPostGISVersion.nMajor <= 1)
    1513                 :         {
    1514                 :             /* Sometimes there is an old cruft entry in the geometry_columns
    1515                 :             * table if things were not properly cleaned up before.  We make
    1516                 :             * an effort to clean out such cruft.
    1517                 :             * Note: PostGIS 2.0 defines geometry_columns as a view (no clean up is needed)
    1518                 :             */
    1519                 :             osCommand.Printf(
    1520                 :                     "DELETE FROM geometry_columns WHERE f_table_name = %s AND f_table_schema = '%s'",
    1521              31 :                     pszEscapedTableNameSingleQuote, pszSchemaName );
    1522                 : 
    1523              31 :             hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
    1524              31 :             OGRPGClearResult( hResult );
    1525                 :         }
    1526                 : 
    1527                 :         osCommand.Printf(
    1528                 :                  "SELECT AddGeometryColumn('%s',%s,'%s',%d,'%s',%d)",
    1529                 :                  pszSchemaName, pszEscapedTableNameSingleQuote, pszGFldName,
    1530              31 :                  nSRSId, pszGeometryType, nDimension );
    1531                 : 
    1532              31 :         hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
    1533                 : 
    1534              31 :         if( !hResult
    1535                 :             || PQresultStatus(hResult) != PGRES_TUPLES_OK )
    1536                 :         {
    1537                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1538                 :                       "AddGeometryColumn failed for layer %s, layer creation has failed.",
    1539               1 :                       pszLayerName );
    1540                 : 
    1541               1 :             CPLFree( pszTableName );
    1542               1 :             CPLFree( pszSchemaName );
    1543                 : 
    1544               1 :             OGRPGClearResult( hResult );
    1545                 : 
    1546               1 :             hResult = OGRPG_PQexec(hPGConn, "ROLLBACK");
    1547               1 :             OGRPGClearResult( hResult );
    1548                 : 
    1549               1 :             return NULL;
    1550                 :         }
    1551                 : 
    1552              30 :         OGRPGClearResult( hResult );
    1553                 :     }
    1554                 :     
    1555              55 :     if( eType != wkbNone && bHavePostGIS )
    1556                 :     {
    1557                 : /* -------------------------------------------------------------------- */
    1558                 : /*      Create the spatial index.                                       */
    1559                 : /*                                                                      */
    1560                 : /*      We're doing this before we add geometry and record to the table */
    1561                 : /*      so this may not be exactly the best way to do it.               */
    1562                 : /* -------------------------------------------------------------------- */
    1563              31 :         const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
    1564              31 :         if( pszSI == NULL || CSLTestBoolean(pszSI) )
    1565                 :         {
    1566                 :             osCommand.Printf("CREATE INDEX \"%s_geom_idx\" "
    1567                 :                              "ON \"%s\".\"%s\" "
    1568                 :                              "USING GIST (%s)",
    1569                 :                              pszTableName, pszSchemaName, pszTableName,
    1570              31 :                              OGRPGEscapeColumnName(pszGFldName).c_str());
    1571                 : 
    1572              31 :             hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
    1573                 : 
    1574              31 :             if( !hResult
    1575                 :                 || PQresultStatus(hResult) != PGRES_COMMAND_OK )
    1576                 :             {
    1577                 :                 CPLError( CE_Failure, CPLE_AppDefined,
    1578                 :                         "'%s' failed for layer %s, index creation has failed.",
    1579               0 :                         osCommand.c_str(), pszLayerName );
    1580                 : 
    1581               0 :                 CPLFree( pszTableName );
    1582               0 :                 CPLFree( pszSchemaName );
    1583                 : 
    1584               0 :                 OGRPGClearResult( hResult );
    1585                 : 
    1586               0 :                 hResult = OGRPG_PQexec(hPGConn, "ROLLBACK");
    1587               0 :                 OGRPGClearResult( hResult );
    1588                 : 
    1589               0 :                 return NULL;
    1590                 :             }
    1591              31 :             OGRPGClearResult( hResult );
    1592                 :         }
    1593                 :     }
    1594                 : 
    1595                 : /* -------------------------------------------------------------------- */
    1596                 : /*      Complete, and commit the transaction.                           */
    1597                 : /* -------------------------------------------------------------------- */
    1598              55 :     hResult = OGRPG_PQexec(hPGConn, "COMMIT");
    1599              55 :     OGRPGClearResult( hResult );
    1600                 : 
    1601                 : /* -------------------------------------------------------------------- */
    1602                 : /*      Create the layer object.                                        */
    1603                 : /* -------------------------------------------------------------------- */
    1604                 :     OGRPGTableLayer     *poLayer;
    1605                 : 
    1606              55 :     poLayer = new OGRPGTableLayer( this, osCurrentSchema, pszTableName, pszSchemaName, NULL, TRUE, FALSE, nSRSId);
    1607             110 :     if( poLayer->GetLayerDefnCanReturnNULL() == NULL )
    1608                 :     {
    1609               0 :         CPLFree( pszTableName );
    1610               0 :         CPLFree( pszSchemaName );
    1611               0 :         delete poLayer;
    1612               0 :         return NULL;
    1613                 :     }
    1614                 : 
    1615              55 :     poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
    1616              55 :     poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
    1617                 :     
    1618              55 :     const char* pszHSTOREColumns = CSLFetchNameValue( papszOptions, "HSTORE_COLUMNS" );
    1619              55 :     poLayer->SetHSTOREColumns(pszHSTOREColumns);
    1620                 : 
    1621                 : /* -------------------------------------------------------------------- */
    1622                 : /*      Add layer to data source layer list.                            */
    1623                 : /* -------------------------------------------------------------------- */
    1624                 :     papoLayers = (OGRPGTableLayer **)
    1625              55 :         CPLRealloc( papoLayers,  sizeof(OGRPGTableLayer *) * (nLayers+1) );
    1626                 : 
    1627              55 :     papoLayers[nLayers++] = poLayer;
    1628                 : 
    1629              55 :     CPLFree( pszTableName );
    1630              55 :     CPLFree( pszSchemaName );
    1631                 : 
    1632              55 :     return poLayer;
    1633                 : }
    1634                 : 
    1635                 : /************************************************************************/
    1636                 : /*                           TestCapability()                           */
    1637                 : /************************************************************************/
    1638                 : 
    1639              13 : int OGRPGDataSource::TestCapability( const char * pszCap )
    1640                 : 
    1641                 : {
    1642              13 :     if( EQUAL(pszCap,ODsCCreateLayer) 
    1643                 :         || EQUAL(pszCap,ODsCDeleteLayer) )
    1644               9 :         return TRUE;
    1645                 :     else
    1646               4 :         return FALSE;
    1647                 : }
    1648                 : 
    1649                 : /************************************************************************/
    1650                 : /*                              GetLayer()                              */
    1651                 : /************************************************************************/
    1652                 : 
    1653            4580 : OGRLayer *OGRPGDataSource::GetLayer( int iLayer )
    1654                 : 
    1655                 : {
    1656            4580 :     if( iLayer < 0 || iLayer >= nLayers )
    1657               8 :         return NULL;
    1658                 :     else
    1659            4572 :         return papoLayers[iLayer];
    1660                 : }
    1661                 : 
    1662                 : /************************************************************************/
    1663                 : /*                           GetLayerByName()                           */
    1664                 : /************************************************************************/
    1665                 : 
    1666             211 : OGRLayer *OGRPGDataSource::GetLayerByName( const char *pszName )
    1667                 : 
    1668                 : {
    1669             211 :     char* pszTableName = NULL;
    1670             211 :     char *pszGeomColumnName = NULL;
    1671             211 :     char *pszSchemaName = NULL;
    1672                 : 
    1673             211 :     if ( ! pszName )
    1674               0 :         return NULL;
    1675                 : 
    1676                 :     int  i;
    1677                 :     
    1678             211 :     int count = GetLayerCount();
    1679                 :     /* first a case sensitive check */
    1680           25836 :     for( i = 0; i < count; i++ )
    1681                 :     {
    1682           25733 :         OGRPGTableLayer *poLayer = papoLayers[i];
    1683                 : 
    1684           25733 :         if( strcmp( pszName, poLayer->GetName() ) == 0 )
    1685                 :         {
    1686             108 :             return poLayer;
    1687                 :         }
    1688                 :     }
    1689                 :         
    1690                 :     /* then case insensitive */
    1691           14495 :     for( i = 0; i < count; i++ )
    1692                 :     {
    1693           14392 :         OGRPGTableLayer *poLayer = papoLayers[i];
    1694                 : 
    1695           14392 :         if( EQUAL( pszName, poLayer->GetName() ) )
    1696                 :         {
    1697               0 :             return poLayer;
    1698                 :         }
    1699                 :     }
    1700                 : 
    1701             103 :     char* pszNameWithoutBracket = CPLStrdup(pszName);
    1702             103 :     char *pos = strchr(pszNameWithoutBracket, '(');
    1703             103 :     if (pos != NULL)
    1704                 :     {
    1705               1 :         *pos = '\0';
    1706               1 :         pszGeomColumnName = CPLStrdup(pos+1);
    1707               1 :         int len = strlen(pszGeomColumnName);
    1708               1 :         if (len > 0)
    1709               1 :             pszGeomColumnName[len - 1] = '\0';
    1710                 :     }
    1711                 : 
    1712             103 :     pos = strchr(pszNameWithoutBracket, '.');
    1713             103 :     if (pos != NULL)
    1714                 :     {
    1715              22 :         *pos = '\0';
    1716              22 :         pszSchemaName = CPLStrdup(pszNameWithoutBracket);
    1717              22 :         pszTableName = CPLStrdup(pos + 1);
    1718                 :     }
    1719                 :     else
    1720                 :     {
    1721              81 :         pszTableName = CPLStrdup(pszNameWithoutBracket);
    1722                 :     }
    1723             103 :     CPLFree(pszNameWithoutBracket);
    1724             103 :     pszNameWithoutBracket = NULL;
    1725                 : 
    1726             103 :     OGRLayer* poLayer = NULL;
    1727                 : 
    1728             103 :     if (pszSchemaName != NULL && osCurrentSchema == pszSchemaName &&
    1729                 :         pszGeomColumnName == NULL )
    1730                 :     {
    1731              16 :         poLayer = GetLayerByName(pszTableName);
    1732                 :     }
    1733                 :     else
    1734                 :     {
    1735                 :         poLayer = OpenTable( osCurrentSchema, pszTableName,
    1736                 :                              pszSchemaName,
    1737                 :                              pszGeomColumnName,
    1738              87 :                              bDSUpdate, TRUE, TRUE );
    1739                 :     }
    1740                 : 
    1741             103 :     CPLFree(pszTableName);
    1742             103 :     CPLFree(pszSchemaName);
    1743             103 :     CPLFree(pszGeomColumnName);
    1744                 : 
    1745             103 :     return poLayer;
    1746                 : }
    1747                 : 
    1748                 : 
    1749                 : /************************************************************************/
    1750                 : /*                        OGRPGNoticeProcessor()                        */
    1751                 : /************************************************************************/
    1752                 : 
    1753             125 : static void OGRPGNoticeProcessor( void *arg, const char * pszMessage )
    1754                 : 
    1755                 : {
    1756             125 :     CPLDebug( "OGR_PG_NOTICE", "%s", pszMessage );
    1757             125 : }
    1758                 : 
    1759                 : /************************************************************************/
    1760                 : /*                      InitializeMetadataTables()                      */
    1761                 : /*                                                                      */
    1762                 : /*      Create the metadata tables (SPATIAL_REF_SYS and                 */
    1763                 : /*      GEOMETRY_COLUMNS).                                              */
    1764                 : /************************************************************************/
    1765                 : 
    1766               0 : OGRErr OGRPGDataSource::InitializeMetadataTables()
    1767                 : 
    1768                 : {
    1769                 :     // implement later.
    1770               0 :     return OGRERR_FAILURE;
    1771                 : }
    1772                 : 
    1773                 : /************************************************************************/
    1774                 : /*                              FetchSRS()                              */
    1775                 : /*                                                                      */
    1776                 : /*      Return a SRS corresponding to a particular id.  Note that       */
    1777                 : /*      reference counting should be honoured on the returned           */
    1778                 : /*      OGRSpatialReference, as handles may be cached.                  */
    1779                 : /************************************************************************/
    1780                 : 
    1781               6 : OGRSpatialReference *OGRPGDataSource::FetchSRS( int nId )
    1782                 : 
    1783                 : {
    1784               6 :     if( nId < 0 )
    1785               0 :         return NULL;
    1786                 : 
    1787                 : /* -------------------------------------------------------------------- */
    1788                 : /*      First, we look through our SRID cache, is it there?             */
    1789                 : /* -------------------------------------------------------------------- */
    1790                 :     int  i;
    1791                 : 
    1792               7 :     for( i = 0; i < nKnownSRID; i++ )
    1793                 :     {
    1794               2 :         if( panSRID[i] == nId )
    1795               1 :             return papoSRS[i];
    1796                 :     }
    1797                 : 
    1798                 : /* -------------------------------------------------------------------- */
    1799                 : /*      Try looking up in spatial_ref_sys table.                        */
    1800                 : /* -------------------------------------------------------------------- */
    1801               5 :     PGresult        *hResult = NULL;
    1802               5 :     CPLString        osCommand;
    1803               5 :     OGRSpatialReference *poSRS = NULL;
    1804                 : 
    1805               5 :     SoftStartTransaction();
    1806                 : 
    1807                 :     osCommand.Printf(
    1808                 :              "SELECT srtext FROM spatial_ref_sys "
    1809                 :              "WHERE srid = %d",
    1810               5 :              nId );
    1811               5 :     hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
    1812                 : 
    1813               5 :     if( hResult
    1814                 :         && PQresultStatus(hResult) == PGRES_TUPLES_OK
    1815                 :         && PQntuples(hResult) == 1 )
    1816                 :     {
    1817                 :         char *pszWKT;
    1818                 : 
    1819               5 :         pszWKT = PQgetvalue(hResult,0,0);
    1820               5 :         poSRS = new OGRSpatialReference();
    1821              10 :         if( poSRS->importFromWkt( &pszWKT ) != OGRERR_NONE )
    1822                 :         {
    1823               0 :             delete poSRS;
    1824               0 :             poSRS = NULL;
    1825                 :         }
    1826                 :     }
    1827                 :     else
    1828                 :     {
    1829                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1830               0 :                   "Could not fetch SRS: %s", PQerrorMessage( hPGConn ) );
    1831                 :     }
    1832                 : 
    1833               5 :     OGRPGClearResult( hResult );
    1834               5 :     SoftCommit();
    1835                 : 
    1836                 : /* -------------------------------------------------------------------- */
    1837                 : /*      Add to the cache.                                               */
    1838                 : /* -------------------------------------------------------------------- */
    1839               5 :     panSRID = (int *) CPLRealloc(panSRID,sizeof(int) * (nKnownSRID+1) );
    1840                 :     papoSRS = (OGRSpatialReference **)
    1841               5 :         CPLRealloc(papoSRS, sizeof(void*) * (nKnownSRID + 1) );
    1842               5 :     panSRID[nKnownSRID] = nId;
    1843               5 :     papoSRS[nKnownSRID] = poSRS;
    1844               5 :     nKnownSRID++;
    1845                 : 
    1846               5 :     return poSRS;
    1847                 : }
    1848                 : 
    1849                 : /************************************************************************/
    1850                 : /*                             FetchSRSId()                             */
    1851                 : /*                                                                      */
    1852                 : /*      Fetch the id corresponding to an SRS, and if not found, add     */
    1853                 : /*      it to the table.                                                */
    1854                 : /************************************************************************/
    1855                 : 
    1856              13 : int OGRPGDataSource::FetchSRSId( OGRSpatialReference * poSRS )
    1857                 : 
    1858                 : {
    1859              13 :     PGresult            *hResult = NULL;
    1860              13 :     CPLString           osCommand;
    1861              13 :     char                *pszWKT = NULL;
    1862              13 :     int                 nSRSId = nUndefinedSRID;
    1863                 :     const char*         pszAuthorityName;
    1864                 : 
    1865              13 :     if( poSRS == NULL )
    1866               0 :         return nUndefinedSRID;
    1867                 : 
    1868              13 :     OGRSpatialReference oSRS(*poSRS);
    1869              13 :     poSRS = NULL;
    1870                 : 
    1871              13 :     pszAuthorityName = oSRS.GetAuthorityName(NULL);
    1872                 : 
    1873              13 :     if( pszAuthorityName == NULL || strlen(pszAuthorityName) == 0 )
    1874                 :     {
    1875                 : /* -------------------------------------------------------------------- */
    1876                 : /*      Try to identify an EPSG code                                    */
    1877                 : /* -------------------------------------------------------------------- */
    1878               8 :         oSRS.AutoIdentifyEPSG();
    1879                 : 
    1880               8 :         pszAuthorityName = oSRS.GetAuthorityName(NULL);
    1881               8 :         if (pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG"))
    1882                 :         {
    1883               1 :             const char* pszAuthorityCode = oSRS.GetAuthorityCode(NULL);
    1884               1 :             if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
    1885                 :             {
    1886                 :                 /* Import 'clean' SRS */
    1887               1 :                 oSRS.importFromEPSG( atoi(pszAuthorityCode) );
    1888                 : 
    1889               1 :                 pszAuthorityName = oSRS.GetAuthorityName(NULL);
    1890                 :             }
    1891                 :         }
    1892                 :     }
    1893                 : /* -------------------------------------------------------------------- */
    1894                 : /*      Check whether the EPSG authority code is already mapped to a    */
    1895                 : /*      SRS ID.                                                         */
    1896                 : /* -------------------------------------------------------------------- */
    1897              13 :     if( pszAuthorityName != NULL && EQUAL( pszAuthorityName, "EPSG" ) )
    1898                 :     {
    1899                 :         int             nAuthorityCode;
    1900                 : 
    1901                 :         /* For the root authority name 'EPSG', the authority code
    1902                 :          * should always be integral
    1903                 :          */
    1904               6 :         nAuthorityCode = atoi( oSRS.GetAuthorityCode(NULL) );
    1905                 : 
    1906                 :         osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE "
    1907                 :                          "auth_name = '%s' AND auth_srid = %d",
    1908                 :                          pszAuthorityName,
    1909               6 :                          nAuthorityCode );
    1910               6 :         hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
    1911                 : 
    1912               6 :         if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
    1913                 :             && PQntuples(hResult) > 0 )
    1914                 :         {
    1915               3 :             nSRSId = atoi(PQgetvalue( hResult, 0, 0 ));
    1916                 : 
    1917               3 :             OGRPGClearResult( hResult );
    1918                 : 
    1919               3 :             return nSRSId;
    1920                 :         }
    1921                 : 
    1922               3 :         OGRPGClearResult( hResult );
    1923                 :     }
    1924                 : 
    1925                 : /* -------------------------------------------------------------------- */
    1926                 : /*      Translate SRS to WKT.                                           */
    1927                 : /* -------------------------------------------------------------------- */
    1928              10 :     if( oSRS.exportToWkt( &pszWKT ) != OGRERR_NONE )
    1929                 :     {
    1930               0 :         CPLFree(pszWKT);
    1931               0 :         return nUndefinedSRID;
    1932                 :     }
    1933                 : 
    1934                 : /* -------------------------------------------------------------------- */
    1935                 : /*      Try to find in the existing table.                              */
    1936                 : /* -------------------------------------------------------------------- */
    1937              10 :     hResult = OGRPG_PQexec(hPGConn, "BEGIN");
    1938              10 :     OGRPGClearResult( hResult );
    1939                 : 
    1940              10 :     CPLString osWKT = OGRPGEscapeString(hPGConn, pszWKT, -1, "spatial_ref_sys", "srtext");
    1941                 :     osCommand.Printf(
    1942                 :              "SELECT srid FROM spatial_ref_sys WHERE srtext = %s",
    1943              10 :              osWKT.c_str() );
    1944              10 :     hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
    1945              10 :     CPLFree( pszWKT );  // CM:  Added to prevent mem leaks
    1946              10 :     pszWKT = NULL;      // CM:  Added
    1947                 : 
    1948                 : /* -------------------------------------------------------------------- */
    1949                 : /*      We got it!  Return it.                                          */
    1950                 : /* -------------------------------------------------------------------- */
    1951              10 :     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
    1952                 :         && PQntuples(hResult) > 0 )
    1953                 :     {
    1954               4 :         nSRSId = atoi(PQgetvalue( hResult, 0, 0 ));
    1955                 : 
    1956               4 :         OGRPGClearResult( hResult );
    1957                 : 
    1958               4 :         hResult = OGRPG_PQexec(hPGConn, "COMMIT");
    1959               4 :         OGRPGClearResult( hResult );
    1960                 : 
    1961               4 :         return nSRSId;
    1962                 :     }
    1963                 : 
    1964                 : /* -------------------------------------------------------------------- */
    1965                 : /*      If the command actually failed, then the metadata table is      */
    1966                 : /*      likely missing. Try defining it.                                */
    1967                 : /* -------------------------------------------------------------------- */
    1968                 :     int         bTableMissing;
    1969                 : 
    1970                 :     bTableMissing =
    1971               6 :         hResult == NULL || PQresultStatus(hResult) == PGRES_NONFATAL_ERROR;
    1972                 : 
    1973               6 :     OGRPGClearResult( hResult );
    1974                 : 
    1975               6 :     hResult = OGRPG_PQexec(hPGConn, "COMMIT");
    1976               6 :     OGRPGClearResult( hResult );
    1977                 : 
    1978               6 :     if( bTableMissing )
    1979                 :     {
    1980               0 :         if( InitializeMetadataTables() != OGRERR_NONE )
    1981               0 :             return nUndefinedSRID;
    1982                 :     }
    1983                 : 
    1984                 : /* -------------------------------------------------------------------- */
    1985                 : /*      Get the current maximum srid in the srs table.                  */
    1986                 : /* -------------------------------------------------------------------- */
    1987               6 :     hResult = OGRPG_PQexec(hPGConn, "BEGIN");
    1988               6 :     OGRPGClearResult( hResult );
    1989                 : 
    1990               6 :     hResult = OGRPG_PQexec(hPGConn, "SELECT MAX(srid) FROM spatial_ref_sys" );
    1991                 : 
    1992               6 :     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK )
    1993                 :     {
    1994               6 :         nSRSId = atoi(PQgetvalue(hResult,0,0)) + 1;
    1995               6 :         OGRPGClearResult( hResult );
    1996                 :     }
    1997                 :     else
    1998                 :     {
    1999               0 :         nSRSId = 1;
    2000                 :     }
    2001                 : 
    2002                 : /* -------------------------------------------------------------------- */
    2003                 : /*      Try adding the SRS to the SRS table.                            */
    2004                 : /* -------------------------------------------------------------------- */
    2005               6 :     char    *pszProj4 = NULL;
    2006               6 :     if( oSRS.exportToProj4( &pszProj4 ) != OGRERR_NONE )
    2007                 :     {
    2008               0 :         CPLFree( pszProj4 );
    2009               0 :         return nUndefinedSRID;
    2010                 :     }
    2011                 : 
    2012               6 :     CPLString osProj4 = OGRPGEscapeString(hPGConn, pszProj4, -1, "spatial_ref_sys", "proj4text");
    2013                 : 
    2014               9 :     if( pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG") )
    2015                 :     {
    2016                 :         int             nAuthorityCode;
    2017                 : 
    2018               3 :         nAuthorityCode = atoi( oSRS.GetAuthorityCode(NULL) );
    2019                 : 
    2020                 :         osCommand.Printf(
    2021                 :                  "INSERT INTO spatial_ref_sys (srid,srtext,proj4text,auth_name,auth_srid) "
    2022                 :                  "VALUES (%d, %s, %s, '%s', %d)",
    2023                 :                  nSRSId, osWKT.c_str(), osProj4.c_str(),
    2024               3 :                  pszAuthorityName, nAuthorityCode );
    2025                 :     }
    2026                 :     else
    2027                 :     {
    2028                 :         osCommand.Printf(
    2029                 :                  "INSERT INTO spatial_ref_sys (srid,srtext,proj4text) VALUES (%d,%s,%s)",
    2030               3 :                  nSRSId, osWKT.c_str(), osProj4.c_str() );
    2031                 :     }
    2032                 : 
    2033                 :     // Free everything that was allocated.
    2034               6 :     CPLFree( pszProj4 );
    2035               6 :     CPLFree( pszWKT);
    2036                 : 
    2037               6 :     hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
    2038               6 :     OGRPGClearResult( hResult );
    2039                 : 
    2040               6 :     hResult = OGRPG_PQexec(hPGConn, "COMMIT");
    2041               6 :     OGRPGClearResult( hResult );
    2042                 : 
    2043               6 :     return nSRSId;
    2044                 : }
    2045                 : 
    2046                 : /************************************************************************/
    2047                 : /*                        SoftStartTransaction()                        */
    2048                 : /*                                                                      */
    2049                 : /*      Create a transaction scope.  If we already have a               */
    2050                 : /*      transaction active this isn't a real transaction, but just      */
    2051                 : /*      an increment to the scope count.                                */
    2052                 : /************************************************************************/
    2053                 : 
    2054            5708 : OGRErr OGRPGDataSource::SoftStartTransaction()
    2055                 : 
    2056                 : {
    2057            5708 :     nSoftTransactionLevel++;
    2058                 : 
    2059            5708 :     if( nSoftTransactionLevel == 1 )
    2060                 :     {
    2061             593 :         PGresult    *hResult = NULL;
    2062             593 :         PGconn      *hPGConn = GetPGConn();
    2063                 : 
    2064                 :         //CPLDebug( "PG", "BEGIN Transaction" );
    2065             593 :         hResult = OGRPG_PQexec(hPGConn, "BEGIN");
    2066                 : 
    2067             593 :         if( !hResult || PQresultStatus(hResult) != PGRES_COMMAND_OK )
    2068                 :         {
    2069               0 :             OGRPGClearResult( hResult );
    2070                 : 
    2071                 :             CPLDebug( "PG", "BEGIN Transaction failed:\n%s",
    2072               0 :                       PQerrorMessage( hPGConn ) );
    2073               0 :             return OGRERR_FAILURE;
    2074                 :         }
    2075                 : 
    2076             593 :         OGRPGClearResult( hResult );
    2077                 :     }
    2078                 : 
    2079            5708 :     return OGRERR_NONE;
    2080                 : }
    2081                 : 
    2082                 : /************************************************************************/
    2083                 : /*                             SoftCommit()                             */
    2084                 : /*                                                                      */
    2085                 : /*      Commit the current transaction if we are at the outer           */
    2086                 : /*      scope.                                                          */
    2087                 : /************************************************************************/
    2088                 : 
    2089            5698 : OGRErr OGRPGDataSource::SoftCommit()
    2090                 : 
    2091                 : {
    2092            5698 :     EndCopy();
    2093                 : 
    2094            5698 :     if( nSoftTransactionLevel <= 0 )
    2095                 :     {
    2096               0 :         CPLDebug( "PG", "SoftCommit() with no transaction active." );
    2097               0 :         return OGRERR_FAILURE;
    2098                 :     }
    2099                 : 
    2100            5698 :     nSoftTransactionLevel--;
    2101                 : 
    2102            5698 :     if( nSoftTransactionLevel == 0 )
    2103                 :     {
    2104             585 :         PGresult    *hResult = NULL;
    2105             585 :         PGconn      *hPGConn = GetPGConn();
    2106                 : 
    2107                 :         //CPLDebug( "PG", "COMMIT Transaction" );
    2108             585 :         hResult = OGRPG_PQexec(hPGConn, "COMMIT");
    2109                 : 
    2110             585 :         if( !hResult || PQresultStatus(hResult) != PGRES_COMMAND_OK )
    2111                 :         {
    2112               0 :             OGRPGClearResult( hResult );
    2113                 : 
    2114                 :             CPLDebug( "PG", "COMMIT Transaction failed:\n%s",
    2115               0 :                       PQerrorMessage( hPGConn ) );
    2116               0 :             return OGRERR_FAILURE;
    2117                 :         }
    2118                 :         
    2119             585 :         OGRPGClearResult( hResult );
    2120                 :     }
    2121                 : 
    2122            5698 :     return OGRERR_NONE;
    2123                 : }
    2124                 : 
    2125                 : /************************************************************************/
    2126                 : /*                            SoftRollback()                            */
    2127                 : /*                                                                      */
    2128                 : /*      Force a rollback of the current transaction if there is one,    */
    2129                 : /*      even if we are nested several levels deep.                      */
    2130                 : /************************************************************************/
    2131                 : 
    2132              10 : OGRErr OGRPGDataSource::SoftRollback()
    2133                 : 
    2134                 : {
    2135              10 :     if( nSoftTransactionLevel <= 0 )
    2136                 :     {
    2137               2 :         CPLDebug( "PG", "SoftRollback() with no transaction active." );
    2138               2 :         return OGRERR_FAILURE;
    2139                 :     }
    2140                 : 
    2141               8 :     nSoftTransactionLevel = 0;
    2142                 : 
    2143               8 :     PGresult    *hResult = NULL;
    2144               8 :     PGconn      *hPGConn = GetPGConn();
    2145                 : 
    2146               8 :     hResult = OGRPG_PQexec(hPGConn, "ROLLBACK");
    2147                 : 
    2148               8 :     if( !hResult || PQresultStatus(hResult) != PGRES_COMMAND_OK )
    2149                 :     {
    2150               0 :         OGRPGClearResult( hResult );
    2151                 : 
    2152               0 :         return OGRERR_FAILURE;
    2153                 :     }
    2154                 : 
    2155               8 :     OGRPGClearResult( hResult );
    2156                 : 
    2157               8 :     return OGRERR_NONE;
    2158                 : }
    2159                 : 
    2160                 : /************************************************************************/
    2161                 : /*                        FlushSoftTransaction()                        */
    2162                 : /*                                                                      */
    2163                 : /*      Force the unwinding of any active transaction, and it's         */
    2164                 : /*      commit.                                                         */
    2165                 : /************************************************************************/
    2166                 : 
    2167            1729 : OGRErr OGRPGDataSource::FlushSoftTransaction()
    2168                 : 
    2169                 : {
    2170                 :     /* This must come first because of ogr2ogr.  If you want
    2171                 :        to use ogr2ogr with COPY support, then you must specify
    2172                 :        that ogr2ogr does not use transactions.  Thus, 
    2173                 :        nSoftTransactionLevel will always be zero, so this has
    2174                 :        to come first. */
    2175            1729 :     EndCopy(); 
    2176                 : 
    2177            1729 :     if( nSoftTransactionLevel <= 0 )
    2178            1262 :         return OGRERR_NONE;
    2179                 : 
    2180             467 :     nSoftTransactionLevel = 1;
    2181                 : 
    2182             467 :     return SoftCommit();
    2183                 : }
    2184                 : 
    2185                 : 
    2186                 : /************************************************************************/
    2187                 : /*                     OGRPGNoResetResultLayer                          */
    2188                 : /************************************************************************/
    2189                 : 
    2190                 : class OGRPGNoResetResultLayer : public OGRPGLayer
    2191                 : {
    2192                 :   public:
    2193                 :                         OGRPGNoResetResultLayer(OGRPGDataSource *poDSIn,
    2194                 :                                                 PGresult *hResultIn);
    2195                 : 
    2196                 :     virtual             ~OGRPGNoResetResultLayer();
    2197                 : 
    2198                 :     virtual void        ResetReading();
    2199                 : 
    2200               0 :     virtual int         TestCapability( const char * ) { return FALSE; }
    2201                 : 
    2202                 :     virtual OGRFeature *GetNextFeature();
    2203                 : };
    2204                 : 
    2205                 : 
    2206                 : /************************************************************************/
    2207                 : /*                     OGRPGNoResetResultLayer()                        */
    2208                 : /************************************************************************/
    2209                 : 
    2210              32 : OGRPGNoResetResultLayer::OGRPGNoResetResultLayer( OGRPGDataSource *poDSIn,
    2211              32 :                                                   PGresult *hResultIn )
    2212                 : {
    2213              32 :     poDS = poDSIn;
    2214              32 :     poFeatureDefn = ReadResultDefinition(hResultIn);
    2215              32 :     hCursorResult = hResultIn;
    2216              32 :     CreateMapFromFieldNameToIndex();
    2217              32 : }
    2218                 : 
    2219                 : /************************************************************************/
    2220                 : /*                   ~OGRPGNoResetResultLayer()                         */
    2221                 : /************************************************************************/
    2222                 : 
    2223              32 : OGRPGNoResetResultLayer::~OGRPGNoResetResultLayer()
    2224                 : 
    2225                 : {
    2226              32 :     OGRPGClearResult( hCursorResult );
    2227              32 :     hCursorResult = NULL;
    2228              32 : }
    2229                 : 
    2230                 : /************************************************************************/
    2231                 : /*                            ResetReading()                            */
    2232                 : /************************************************************************/
    2233                 : 
    2234              32 : void OGRPGNoResetResultLayer::ResetReading()
    2235                 : {
    2236              32 :     iNextShapeId = 0;
    2237              32 : }
    2238                 : 
    2239                 : /************************************************************************/
    2240                 : /*                           GetNextFeature()                           */
    2241                 : /************************************************************************/
    2242                 : 
    2243              64 : OGRFeature *OGRPGNoResetResultLayer::GetNextFeature()
    2244                 : 
    2245                 : {
    2246              64 :     if (iNextShapeId == PQntuples(hCursorResult))
    2247                 :     {
    2248              32 :         return NULL;
    2249                 :     }
    2250              32 :     return RecordToFeature(iNextShapeId ++);
    2251                 : }
    2252                 : 
    2253                 : /************************************************************************/
    2254                 : /*                      OGRPGMemLayerWrapper                            */
    2255                 : /************************************************************************/
    2256                 : 
    2257                 : class OGRPGMemLayerWrapper : public OGRLayer
    2258                 : {
    2259                 :   private:
    2260                 :       OGRDataSource  *poMemDS;
    2261                 :       OGRLayer       *poMemLayer;
    2262                 : 
    2263                 :   public:
    2264              32 :                         OGRPGMemLayerWrapper( OGRDataSource  *poMemDSIn )
    2265              32 :                         {
    2266              32 :                             poMemDS = poMemDSIn;
    2267              32 :                             poMemLayer = poMemDS->GetLayer(0);
    2268              32 :                         }
    2269                 : 
    2270              32 :                         ~OGRPGMemLayerWrapper() { delete poMemDS; }
    2271                 : 
    2272               0 :     virtual void        ResetReading() { poMemLayer->ResetReading(); }
    2273              19 :     virtual OGRFeature *GetNextFeature() { return poMemLayer->GetNextFeature(); }
    2274               0 :     virtual OGRFeatureDefn *GetLayerDefn() { return poMemLayer->GetLayerDefn(); }
    2275               0 :     virtual int         TestCapability( const char * ) { return FALSE; }
    2276                 : };
    2277                 : 
    2278                 : /************************************************************************/
    2279                 : /*                             ExecuteSQL()                             */
    2280                 : /************************************************************************/
    2281                 : 
    2282             367 : OGRLayer * OGRPGDataSource::ExecuteSQL( const char *pszSQLCommand,
    2283                 :                                         OGRGeometry *poSpatialFilter,
    2284                 :                                         const char *pszDialect )
    2285                 : 
    2286                 : {
    2287                 :     /* Skip leading spaces */
    2288             734 :     while(*pszSQLCommand == ' ')
    2289               0 :         pszSQLCommand ++;
    2290                 :     
    2291                 : /* -------------------------------------------------------------------- */
    2292                 : /*      Use generic implementation for OGRSQL dialect.                  */
    2293                 : /* -------------------------------------------------------------------- */
    2294             367 :     if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
    2295                 :         return OGRDataSource::ExecuteSQL( pszSQLCommand,
    2296                 :                                           poSpatialFilter,
    2297               0 :                                           pszDialect );
    2298                 : 
    2299                 : /* -------------------------------------------------------------------- */
    2300                 : /*      Special case DELLAYER: command.                                 */
    2301                 : /* -------------------------------------------------------------------- */
    2302             367 :     if( EQUALN(pszSQLCommand,"DELLAYER:",9) )
    2303                 :     {
    2304             151 :         const char *pszLayerName = pszSQLCommand + 9;
    2305                 : 
    2306             302 :         while( *pszLayerName == ' ' )
    2307               0 :             pszLayerName++;
    2308                 :         
    2309           19691 :         for( int iLayer = 0; iLayer < nLayers; iLayer++ )
    2310                 :         {
    2311           19601 :             if( EQUAL(papoLayers[iLayer]->GetName(), 
    2312                 :                       pszLayerName ))
    2313                 :             {
    2314              61 :                 DeleteLayer( iLayer );
    2315              61 :                 break;
    2316                 :             }
    2317                 :         }
    2318             151 :         return NULL;
    2319                 :     }
    2320                 : 
    2321                 : /* -------------------------------------------------------------------- */
    2322                 : /*      Execute the statement.                                          */
    2323                 : /* -------------------------------------------------------------------- */
    2324             216 :     PGresult    *hResult = NULL;
    2325                 : 
    2326             216 :     FlushSoftTransaction();
    2327                 : 
    2328             216 :     if( EQUALN(pszSQLCommand,"VACUUM",6) 
    2329                 :         || SoftStartTransaction() == OGRERR_NONE  )
    2330                 :     {
    2331             359 :         if (EQUALN(pszSQLCommand, "SELECT", 6) == FALSE ||
    2332                 :             (strstr(pszSQLCommand, "from") == NULL && strstr(pszSQLCommand, "FROM") == NULL))
    2333                 :         {
    2334             175 :             hResult = OGRPG_PQexec(hPGConn, pszSQLCommand, TRUE /* multiple allowed */ );
    2335             175 :             if (hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK)
    2336                 :             {
    2337              32 :                 CPLDebug( "PG", "Command Results Tuples = %d", PQntuples(hResult) );
    2338              32 :                 FlushSoftTransaction();
    2339                 : 
    2340                 :                 OGRSFDriver* poMemDriver = OGRSFDriverRegistrar::GetRegistrar()->
    2341              32 :                                 GetDriverByName("Memory");
    2342              32 :                 if (poMemDriver)
    2343                 :                 {
    2344              32 :                     OGRPGLayer* poResultLayer = new OGRPGNoResetResultLayer( this, hResult );
    2345              32 :                     OGRDataSource* poMemDS = poMemDriver->CreateDataSource("");
    2346              32 :                     poMemDS->CopyLayer(poResultLayer, "sql_statement");
    2347              64 :                     OGRPGMemLayerWrapper* poResLayer = new OGRPGMemLayerWrapper(poMemDS);
    2348              64 :                     delete poResultLayer;
    2349              32 :                     return poResLayer;
    2350                 :                 }
    2351                 :                 else
    2352               0 :                     return NULL;
    2353                 :             }
    2354                 :         }
    2355                 :         else
    2356                 :         {
    2357              41 :             CPLString osCommand;
    2358                 :             osCommand.Printf( "DECLARE %s CURSOR for %s",
    2359              41 :                                 "executeSQLCursor", pszSQLCommand );
    2360                 : 
    2361              41 :             hResult = OGRPG_PQexec(hPGConn, osCommand );
    2362                 : 
    2363                 : /* -------------------------------------------------------------------- */
    2364                 : /*      Do we have a tuple result? If so, instantiate a results         */
    2365                 : /*      layer for it.                                                   */
    2366                 : /* -------------------------------------------------------------------- */
    2367              41 :             if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
    2368                 :             {
    2369              41 :                 OGRPGResultLayer *poLayer = NULL;
    2370                 : 
    2371              41 :                 OGRPGClearResult( hResult );
    2372                 : 
    2373              41 :                 osCommand.Printf( "FETCH 0 in %s", "executeSQLCursor" );
    2374              41 :                 hResult = OGRPG_PQexec(hPGConn, osCommand );
    2375                 : 
    2376              41 :                 poLayer = new OGRPGResultLayer( this, pszSQLCommand, hResult );
    2377                 : 
    2378              41 :                 OGRPGClearResult( hResult );
    2379                 : 
    2380              41 :                 if( poSpatialFilter != NULL )
    2381               0 :                     poLayer->SetSpatialFilter( poSpatialFilter );
    2382                 : 
    2383              41 :                 return poLayer;
    2384               0 :             }
    2385                 :         }
    2386                 :     }
    2387                 : 
    2388                 : /* -------------------------------------------------------------------- */
    2389                 : /*      Generate an error report if an error occured.                   */
    2390                 : /* -------------------------------------------------------------------- */
    2391             143 :     if( !hResult ||
    2392                 :         (PQresultStatus(hResult) == PGRES_NONFATAL_ERROR
    2393                 :          || PQresultStatus(hResult) == PGRES_FATAL_ERROR ) )
    2394                 :     {
    2395                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2396              13 :                   "%s", PQerrorMessage( hPGConn ) );
    2397                 :     }
    2398                 : 
    2399             143 :     OGRPGClearResult( hResult );
    2400                 : 
    2401             143 :     FlushSoftTransaction();
    2402                 : 
    2403             143 :     return NULL;
    2404                 : }
    2405                 : 
    2406                 : /************************************************************************/
    2407                 : /*                          ReleaseResultSet()                          */
    2408                 : /************************************************************************/
    2409                 : 
    2410              75 : void OGRPGDataSource::ReleaseResultSet( OGRLayer * poLayer )
    2411                 : 
    2412                 : {
    2413              75 :     delete poLayer;
    2414              75 : }
    2415                 : 
    2416                 : /************************************************************************/
    2417                 : /*                            LaunderName()                             */
    2418                 : /************************************************************************/
    2419                 : 
    2420             233 : char *OGRPGDataSource::LaunderName( const char *pszSrcName )
    2421                 : 
    2422                 : {
    2423             233 :     char    *pszSafeName = CPLStrdup( pszSrcName );
    2424                 : 
    2425           22304 :     for( int i = 0; pszSafeName[i] != '\0'; i++ )
    2426                 :     {
    2427           22071 :         pszSafeName[i] = (char) tolower( pszSafeName[i] );
    2428           22071 :         if( pszSafeName[i] == '\'' || pszSafeName[i] == '-' || pszSafeName[i] == '#' )
    2429               0 :             pszSafeName[i] = '_';
    2430                 :     }
    2431                 : 
    2432             233 :     if( strcmp(pszSrcName,pszSafeName) != 0 )
    2433                 :         CPLDebug("PG","LaunderName('%s') -> '%s'", 
    2434              44 :                  pszSrcName, pszSafeName);
    2435                 : 
    2436             233 :     return pszSafeName;
    2437                 : }
    2438                 : 
    2439                 : /************************************************************************/
    2440                 : /*                             StartCopy()                              */
    2441                 : /************************************************************************/
    2442              10 : void OGRPGDataSource::StartCopy( OGRPGTableLayer *poPGLayer )
    2443                 : {
    2444              10 :     EndCopy();
    2445              10 :     poLayerInCopyMode = poPGLayer;
    2446              10 : }
    2447                 : 
    2448                 : /************************************************************************/
    2449                 : /*                              EndCopy()                               */
    2450                 : /************************************************************************/
    2451            7437 : OGRErr OGRPGDataSource::EndCopy( )
    2452                 : {
    2453            7437 :     if( poLayerInCopyMode != NULL )
    2454                 :     {
    2455              10 :         OGRErr result = poLayerInCopyMode->EndCopy();
    2456              10 :         poLayerInCopyMode = NULL;
    2457                 : 
    2458              10 :         return result;
    2459                 :     }
    2460                 :     else
    2461            7427 :         return OGRERR_NONE;
    2462                 : }
    2463                 : 
    2464                 : /************************************************************************/
    2465                 : /*                           CopyInProgress()                           */
    2466                 : /************************************************************************/
    2467               0 : int OGRPGDataSource::CopyInProgress( )
    2468                 : {
    2469               0 :     return ( poLayerInCopyMode != NULL );
    2470                 : }

Generated by: LCOV version 1.7