LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpgdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 951 819 86.1 %
Date: 2012-04-28 Functions: 50 37 74.0 %

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

Generated by: LCOV version 1.7