LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpglayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 886 515 58.1 %
Date: 2012-04-28 Functions: 37 27 73.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpglayer.cpp 23565 2011-12-13 20:33:20Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGRPGLayer class  which implements shared handling
       6                 :  *           of feature geometry and so forth needed by OGRPGResultLayer and
       7                 :  *           OGRPGTableLayer.
       8                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       9                 :  *
      10                 :  ******************************************************************************
      11                 :  * Copyright (c) 2000, Frank Warmerdam
      12                 :  *
      13                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      14                 :  * copy of this software and associated documentation files (the "Software"),
      15                 :  * to deal in the Software without restriction, including without limitation
      16                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      17                 :  * and/or sell copies of the Software, and to permit persons to whom the
      18                 :  * Software is furnished to do so, subject to the following conditions:
      19                 :  *
      20                 :  * The above copyright notice and this permission notice shall be included
      21                 :  * in all copies or substantial portions of the Software.
      22                 :  *
      23                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      24                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      25                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      26                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      27                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      28                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      29                 :  * DEALINGS IN THE SOFTWARE.
      30                 :  ****************************************************************************/
      31                 : 
      32                 : /* Some functions have been extracted from PostgreSQL code base  */
      33                 : /* The applicable copyright & licence notice is the following one : */
      34                 : /*
      35                 : PostgreSQL Database Management System
      36                 : (formerly known as Postgres, then as Postgres95)
      37                 : 
      38                 : Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
      39                 : 
      40                 : Portions Copyright (c) 1994, The Regents of the University of California
      41                 : 
      42                 : Permission to use, copy, modify, and distribute this software and its
      43                 : documentation for any purpose, without fee, and without a written agreement
      44                 : is hereby granted, provided that the above copyright notice and this
      45                 : paragraph and the following two paragraphs appear in all copies.
      46                 : 
      47                 : IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
      48                 : DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
      49                 : LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
      50                 : DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
      51                 : POSSIBILITY OF SUCH DAMAGE.
      52                 : 
      53                 : THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
      54                 : INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      55                 : AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
      56                 : ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
      57                 : PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
      58                 : */
      59                 : 
      60                 : #include "ogr_pg.h"
      61                 : #include "ogr_p.h"
      62                 : #include "cpl_conv.h"
      63                 : #include "cpl_string.h"
      64                 : 
      65                 : #define PQexec this_is_an_error
      66                 : 
      67                 : CPL_CVSID("$Id: ogrpglayer.cpp 23565 2011-12-13 20:33:20Z rouault $");
      68                 : 
      69                 : #define CURSOR_PAGE     500
      70                 : 
      71                 : // These originally are defined in libpq-fs.h.
      72                 : 
      73                 : #ifndef INV_WRITE
      74                 : #define INV_WRITE               0x00020000
      75                 : #define INV_READ                0x00040000
      76                 : #endif
      77                 : 
      78                 : /* Flags for creating WKB format for PostGIS */
      79                 : #define WKBZOFFSET 0x80000000
      80                 : #define WKBMOFFSET 0x40000000
      81                 : #define WKBSRIDFLAG 0x20000000
      82                 : #define WKBBBOXFLAG 0x10000000
      83                 : 
      84                 : /************************************************************************/
      85                 : /*                           OGRPGLayer()                               */
      86                 : /************************************************************************/
      87                 : 
      88           16006 : OGRPGLayer::OGRPGLayer()
      89                 : 
      90                 : {
      91           16006 :     poDS = NULL;
      92                 : 
      93           16006 :     bHasWkb = FALSE;
      94           16006 :     bWkbAsOid = FALSE;
      95           16006 :     bHasPostGISGeometry = FALSE;
      96           16006 :     bHasPostGISGeography = FALSE;
      97           16006 :     pszGeomColumn = NULL;
      98           16006 :     pszQueryStatement = NULL;
      99                 : 
     100           16006 :     bHasFid = FALSE;
     101           16006 :     pszFIDColumn = NULL;
     102                 : 
     103           16006 :     iNextShapeId = 0;
     104           16006 :     nResultOffset = 0;
     105                 : 
     106           16006 :     nCoordDimension = 2; // initialize in case PostGIS is not available
     107                 : 
     108           16006 :     poSRS = NULL;
     109           16006 :     nSRSId = UNDETERMINED_SRID; // we haven't even queried the database for it yet.
     110                 : 
     111           16006 :     pszCursorName = CPLStrdup(CPLSPrintf("OGRPGLayerReader%p", this));
     112                 :     
     113           16006 :     hCursorResult = NULL;
     114                 : 
     115           16006 :     bCanUseBinaryCursor = TRUE;
     116                 : 
     117           16006 :     poFeatureDefn = NULL;
     118           16006 :     panMapFieldNameToIndex = NULL;
     119           16006 : }
     120                 : 
     121                 : /************************************************************************/
     122                 : /*                            ~OGRPGLayer()                             */
     123                 : /************************************************************************/
     124                 : 
     125           16006 : OGRPGLayer::~OGRPGLayer()
     126                 : 
     127                 : {
     128           16006 :     if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
     129                 :     {
     130                 :         CPLDebug( "PG", "%d features read on layer '%s'.",
     131                 :                   (int) m_nFeaturesRead,
     132             232 :                   poFeatureDefn->GetName() );
     133                 :     }
     134                 : 
     135           16006 :     ResetReading();
     136                 : 
     137           16006 :     CPLFree( pszGeomColumn );
     138           16006 :     CPLFree( pszFIDColumn );
     139           16006 :     CPLFree( pszQueryStatement );
     140           16006 :     CPLFree( panMapFieldNameToIndex );
     141           16006 :     CPLFree( pszCursorName );
     142                 : 
     143           16006 :     if( poSRS != NULL )
     144               8 :         poSRS->Release();
     145                 : 
     146           16006 :     if( poFeatureDefn )
     147             576 :         poFeatureDefn->Release();
     148           16006 : }
     149                 : 
     150                 : /************************************************************************/
     151                 : /*                            CloseCursor()                             */
     152                 : /************************************************************************/
     153                 : 
     154           17144 : void OGRPGLayer::CloseCursor()
     155                 : {
     156           17144 :     PGconn      *hPGConn = poDS->GetPGConn();
     157                 : 
     158           17144 :     if( hCursorResult != NULL )
     159                 :     {
     160             406 :         OGRPGClearResult( hCursorResult );
     161                 : 
     162             406 :         CPLString    osCommand;
     163             406 :         osCommand.Printf("CLOSE %s", pszCursorName );
     164                 : 
     165             406 :         hCursorResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
     166             406 :         OGRPGClearResult( hCursorResult );
     167                 : 
     168             406 :         poDS->FlushSoftTransaction();
     169                 : 
     170             406 :         hCursorResult = NULL;
     171                 :     }
     172           17144 : }
     173                 : 
     174                 : /************************************************************************/
     175                 : /*                            ResetReading()                            */
     176                 : /************************************************************************/
     177                 : 
     178           16998 : void OGRPGLayer::ResetReading()
     179                 : 
     180                 : {
     181           16998 :     GetLayerDefn();
     182                 : 
     183           16998 :     iNextShapeId = 0;
     184                 : 
     185           16998 :     CloseCursor();
     186           16998 : }
     187                 : 
     188                 : /************************************************************************/
     189                 : /*                    OGRPGGetStrFromBinaryNumeric()                    */
     190                 : /************************************************************************/
     191                 : 
     192                 : /* Adaptation of get_str_from_var() from pgsql/src/backend/utils/adt/numeric.c */
     193                 : 
     194                 : typedef short NumericDigit;
     195                 : 
     196                 : typedef struct NumericVar
     197                 : {
     198                 :         int     ndigits;    /* # of digits in digits[] - can be 0! */
     199                 :         int     weight;     /* weight of first digit */
     200                 :         int     sign;     /* NUMERIC_POS, NUMERIC_NEG, or NUMERIC_NAN */
     201                 :         int     dscale;     /* display scale */
     202                 :         NumericDigit *digits;   /* base-NBASE digits */
     203                 : } NumericVar;
     204                 : 
     205                 : #define NUMERIC_POS     0x0000
     206                 : #define NUMERIC_NEG     0x4000
     207                 : #define NUMERIC_NAN     0xC000
     208                 : 
     209                 : #define DEC_DIGITS  4
     210                 : /*
     211                 : * get_str_from_var() -
     212                 : *
     213                 : * Convert a var to text representation (guts of numeric_out).
     214                 : * CAUTION: var's contents may be modified by rounding!
     215                 : * Returns a palloc'd string.
     216                 : */
     217                 : static char *
     218               0 : OGRPGGetStrFromBinaryNumeric(NumericVar *var)
     219                 : {
     220                 :         char     *str;
     221                 :         char     *cp;
     222                 :         char     *endcp;
     223                 :         int     i;
     224                 :         int     d;
     225                 :         NumericDigit dig;
     226                 :         NumericDigit d1;
     227                 :         
     228               0 :         int dscale = var->dscale;
     229                 : 
     230                 :         /*
     231                 :         * Allocate space for the result.
     232                 :         *
     233                 :         * i is set to to # of decimal digits before decimal point. dscale is the
     234                 :         * # of decimal digits we will print after decimal point. We may generate
     235                 :         * as many as DEC_DIGITS-1 excess digits at the end, and in addition we
     236                 :         * need room for sign, decimal point, null terminator.
     237                 :         */
     238               0 :         i = (var->weight + 1) * DEC_DIGITS;
     239               0 :         if (i <= 0)
     240               0 :                 i = 1;
     241                 : 
     242               0 :         str = (char*)CPLMalloc(i + dscale + DEC_DIGITS + 2);
     243               0 :         cp = str;
     244                 : 
     245                 :         /*
     246                 :         * Output a dash for negative values
     247                 :         */
     248               0 :         if (var->sign == NUMERIC_NEG)
     249               0 :                 *cp++ = '-';
     250                 : 
     251                 :         /*
     252                 :         * Output all digits before the decimal point
     253                 :         */
     254               0 :         if (var->weight < 0)
     255                 :         {
     256               0 :                 d = var->weight + 1;
     257               0 :                 *cp++ = '0';
     258                 :         }
     259                 :         else
     260                 :         {
     261               0 :                 for (d = 0; d <= var->weight; d++)
     262                 :                 {
     263               0 :                         dig = (d < var->ndigits) ? var->digits[d] : 0;
     264               0 :                         CPL_MSBPTR16(&dig);
     265                 :                         /* In the first digit, suppress extra leading decimal zeroes */
     266                 :                         {
     267               0 :                                 bool    putit = (d > 0);
     268                 : 
     269               0 :                                 d1 = dig / 1000;
     270               0 :                                 dig -= d1 * 1000;
     271               0 :                                 putit |= (d1 > 0);
     272               0 :                                 if (putit)
     273               0 :                                         *cp++ = (char)(d1 + '0');
     274               0 :                                 d1 = dig / 100;
     275               0 :                                 dig -= d1 * 100;
     276               0 :                                 putit |= (d1 > 0);
     277               0 :                                 if (putit)
     278               0 :                                         *cp++ = (char)(d1 + '0');
     279               0 :                                 d1 = dig / 10;
     280               0 :                                 dig -= d1 * 10;
     281               0 :                                 putit |= (d1 > 0);
     282               0 :                                 if (putit)
     283               0 :                                         *cp++ = (char)(d1 + '0');
     284               0 :                                 *cp++ = (char)(dig + '0');
     285                 :                         }
     286                 :                 }
     287                 :         }
     288                 :         
     289                 :                 /*
     290                 :         * If requested, output a decimal point and all the digits that follow it.
     291                 :         * We initially put out a multiple of DEC_DIGITS digits, then truncate if
     292                 :         * needed.
     293                 :         */
     294               0 :         if (dscale > 0)
     295                 :         {
     296               0 :                 *cp++ = '.';
     297               0 :                 endcp = cp + dscale;
     298               0 :                 for (i = 0; i < dscale; d++, i += DEC_DIGITS)
     299                 :                 {
     300               0 :                         dig = (d >= 0 && d < var->ndigits) ? var->digits[d] : 0;
     301               0 :                         CPL_MSBPTR16(&dig);
     302               0 :                         d1 = dig / 1000;
     303               0 :                         dig -= d1 * 1000;
     304               0 :                         *cp++ = (char)(d1 + '0');
     305               0 :                         d1 = dig / 100;
     306               0 :                         dig -= d1 * 100;
     307               0 :                         *cp++ = (char)(d1 + '0');
     308               0 :                         d1 = dig / 10;
     309               0 :                         dig -= d1 * 10;
     310               0 :                         *cp++ = (char)(d1 + '0');
     311               0 :                         *cp++ = (char)(dig + '0');
     312                 :                 }
     313               0 :                 cp = endcp;
     314                 :         }
     315                 : 
     316                 :         /*
     317                 :         * terminate the string and return it
     318                 :         */
     319               0 :         *cp = '\0';
     320               0 :         return str;
     321                 : }
     322                 : 
     323                 : /************************************************************************/
     324                 : /*                         OGRPGj2date()                            */
     325                 : /************************************************************************/
     326                 : 
     327                 : /* Coming from j2date() in pgsql/src/backend/utils/adt/datetime.c */
     328                 : 
     329                 : #define POSTGRES_EPOCH_JDATE  2451545 /* == date2j(2000, 1, 1) */
     330                 : 
     331                 : static
     332               0 : void OGRPGj2date(int jd, int *year, int *month, int *day)
     333                 : {
     334                 :   unsigned int julian;
     335                 :   unsigned int quad;
     336                 :   unsigned int extra;
     337                 :   int     y;
     338                 : 
     339               0 :   julian = jd;
     340               0 :   julian += 32044;
     341               0 :   quad = julian / 146097;
     342               0 :   extra = (julian - quad * 146097) * 4 + 3;
     343               0 :   julian += 60 + quad * 3 + extra / 146097;
     344               0 :   quad = julian / 1461;
     345               0 :   julian -= quad * 1461;
     346               0 :   y = julian * 4 / 1461;
     347                 :   julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
     348               0 :     + 123;
     349               0 :   y += quad * 4;
     350               0 :   *year = y - 4800;
     351               0 :   quad = julian * 2141 / 65536;
     352               0 :   *day = julian - 7834 * quad / 256;
     353               0 :   *month = (quad + 10) % 12 + 1;
     354                 : 
     355                 :   return;
     356                 : } /* j2date() */
     357                 : 
     358                 : 
     359                 : /************************************************************************/
     360                 : /*                              OGRPGdt2time()                          */
     361                 : /************************************************************************/
     362                 : 
     363                 : #define USECS_PER_SEC 1000000
     364                 : #define USECS_PER_MIN   ((GIntBig) 60 * USECS_PER_SEC)
     365                 : #define USECS_PER_HOUR  ((GIntBig) 3600 * USECS_PER_SEC)
     366                 : #define USECS_PER_DAY   ((GIntBig) 3600 * 24 * USECS_PER_SEC)
     367                 : 
     368                 : /* Coming from dt2time() in pgsql/src/backend/utils/adt/timestamp.c */
     369                 : 
     370                 : static
     371                 : void
     372               0 : OGRPGdt2timeInt8(GIntBig jd, int *hour, int *min, int *sec, double *fsec)
     373                 : {
     374                 :   GIntBig   time;
     375                 : 
     376               0 :   time = jd;
     377                 : 
     378               0 :   *hour = (int) (time / USECS_PER_HOUR);
     379               0 :   time -= (GIntBig) (*hour) * USECS_PER_HOUR;
     380               0 :   *min = (int) (time / USECS_PER_MIN);
     381               0 :   time -=  (GIntBig) (*min) * USECS_PER_MIN;
     382               0 :   *sec = (int)time / USECS_PER_SEC;
     383               0 :   *fsec = (double)(time - *sec * USECS_PER_SEC);
     384               0 : } /* dt2time() */
     385                 : 
     386                 : static
     387                 : void
     388               0 : OGRPGdt2timeFloat8(double jd, int *hour, int *min, int *sec, double *fsec)
     389                 : {
     390                 :   double  time;
     391                 : 
     392               0 :   time = jd;
     393                 : 
     394               0 :   *hour = (int) (time / 3600.);
     395               0 :   time -= (*hour) * 3600.;
     396               0 :   *min = (int) (time / 60.);
     397               0 :   time -=  (*min) * 60.;
     398               0 :   *sec = (int)time;
     399               0 :   *fsec = time - *sec;
     400               0 : }
     401                 : 
     402                 : /************************************************************************/
     403                 : /*                        OGRPGTimeStamp2DMYHMS()                       */
     404                 : /************************************************************************/
     405                 : 
     406                 : #define TMODULO(t,q,u) \
     407                 : do { \
     408                 :   (q) = ((t) / (u)); \
     409                 :   if ((q) != 0) (t) -= ((q) * (u)); \
     410                 : } while(0)
     411                 : 
     412                 : /* Coming from timestamp2tm() in pgsql/src/backend/utils/adt/timestamp.c */
     413                 : 
     414                 : static
     415               0 : int OGRPGTimeStamp2DMYHMS(GIntBig dt, int *year, int *month, int *day,
     416                 :                                       int* hour, int* min, int* sec)
     417                 : {
     418                 :         GIntBig date;
     419                 :   GIntBig time;
     420                 :         double fsec;
     421                 : 
     422               0 :         time = dt;
     423               0 :   TMODULO(time, date, USECS_PER_DAY);
     424                 : 
     425               0 :   if (time < 0)
     426                 :   {
     427               0 :     time += USECS_PER_DAY;
     428               0 :     date -= 1;
     429                 :   }
     430                 : 
     431                 :   /* add offset to go from J2000 back to standard Julian date */
     432               0 :   date += POSTGRES_EPOCH_JDATE;
     433                 : 
     434                 :   /* Julian day routine does not work for negative Julian days */
     435               0 :   if (date < 0 || date > (double) INT_MAX)
     436               0 :     return -1;
     437                 : 
     438               0 :   OGRPGj2date((int) date, year, month, day);
     439               0 :   OGRPGdt2timeInt8(time, hour, min, sec, &fsec);
     440                 : 
     441               0 :         return 0;
     442                 : }
     443                 : 
     444                 : 
     445                 : /************************************************************************/
     446                 : /*                   TokenizeStringListFromText()                       */
     447                 : /*                                                                      */
     448                 : /* Tokenize a varchar[] returned as a text                              */
     449                 : /************************************************************************/
     450                 : 
     451             192 : static void OGRPGTokenizeStringListUnescapeToken(char* pszToken)
     452                 : {
     453             192 :     if (EQUAL(pszToken, "NULL"))
     454                 :     {
     455               0 :         pszToken[0] = '\0';
     456               0 :         return;
     457                 :     }
     458                 : 
     459             192 :     int iSrc = 0, iDst = 0;
     460             512 :     for(iSrc = 0; pszToken[iSrc] != '\0'; iSrc++)
     461                 :     {
     462             320 :         pszToken[iDst] = pszToken[iSrc];
     463             320 :         if (pszToken[iSrc] != '\\')
     464             320 :             iDst ++;
     465                 :     }
     466             192 :     pszToken[iDst] = '\0';
     467                 : }
     468                 : 
     469                 : /* {"a\",b",d,NULL,e}  should be tokenized into 3 pieces :  a",b     d    empty_string    e */
     470              96 : static char ** OGRPGTokenizeStringListFromText(const char* pszText)
     471                 : {
     472              96 :     char** papszTokens = NULL;
     473              96 :     const char* pszCur = strchr(pszText, '{');
     474              96 :     if (pszCur == NULL)
     475                 :     {
     476               0 :         CPLError(CE_Warning, CPLE_AppDefined, "Incorrect string list : %s", pszText);
     477               0 :         return papszTokens;
     478                 :     }
     479                 : 
     480              96 :     const char* pszNewTokenStart = NULL;
     481              96 :     int bInDoubleQuotes = FALSE;
     482              96 :     pszCur ++;
     483             608 :     while(*pszCur)
     484                 :     {
     485             512 :         if (*pszCur == '\\')
     486                 :         {
     487               0 :             pszCur ++;
     488               0 :             if (*pszCur == 0)
     489               0 :                 break;
     490               0 :             pszCur ++;
     491               0 :             continue;
     492                 :         }
     493                 : 
     494             512 :         if (*pszCur == '"')
     495                 :         {
     496               0 :             bInDoubleQuotes = !bInDoubleQuotes;
     497               0 :             if (bInDoubleQuotes)
     498               0 :                 pszNewTokenStart = pszCur + 1;
     499                 :             else
     500                 :             {
     501               0 :                 if (pszCur[1] == ',' || pszCur[1] == '}')
     502                 :                 {
     503               0 :                     if (pszNewTokenStart != NULL && pszCur > pszNewTokenStart)
     504                 :                     {
     505               0 :                         char* pszNewToken = (char*) CPLMalloc(pszCur - pszNewTokenStart + 1);
     506               0 :                         memcpy(pszNewToken, pszNewTokenStart, pszCur - pszNewTokenStart);
     507               0 :                         pszNewToken[pszCur - pszNewTokenStart] = 0;
     508               0 :                         OGRPGTokenizeStringListUnescapeToken(pszNewToken);
     509               0 :                         papszTokens = CSLAddString(papszTokens, pszNewToken);
     510               0 :                         CPLFree(pszNewToken);
     511                 :                     }
     512               0 :                     pszNewTokenStart = NULL;
     513               0 :                     if (pszCur[1] == ',')
     514               0 :                         pszCur ++;
     515                 :                     else
     516               0 :                         return papszTokens;
     517                 :                 }
     518                 :                 else
     519                 :                 {
     520                 :                     /* error */
     521               0 :                     break;
     522                 :                 }
     523                 :             }
     524                 :         }
     525             512 :         if (!bInDoubleQuotes)
     526                 :         {
     527             512 :             if (*pszCur == '{')
     528                 :             {
     529                 :                 /* error */
     530               0 :                 break;
     531                 :             }
     532             512 :             else if (*pszCur == '}')
     533                 :             {
     534              96 :                 if (pszNewTokenStart != NULL && pszCur > pszNewTokenStart)
     535                 :                 {
     536              96 :                     char* pszNewToken = (char*) CPLMalloc(pszCur - pszNewTokenStart + 1);
     537              96 :                     memcpy(pszNewToken, pszNewTokenStart, pszCur - pszNewTokenStart);
     538              96 :                     pszNewToken[pszCur - pszNewTokenStart] = 0;
     539              96 :                     OGRPGTokenizeStringListUnescapeToken(pszNewToken);
     540              96 :                     papszTokens = CSLAddString(papszTokens, pszNewToken);
     541              96 :                     CPLFree(pszNewToken);
     542                 :                 }
     543              96 :                 return papszTokens;
     544                 :             }
     545             416 :             else if (*pszCur == ',')
     546                 :             {
     547              96 :                 if (pszNewTokenStart != NULL && pszCur > pszNewTokenStart)
     548                 :                 {
     549              96 :                     char* pszNewToken = (char*) CPLMalloc(pszCur - pszNewTokenStart + 1);
     550              96 :                     memcpy(pszNewToken, pszNewTokenStart, pszCur - pszNewTokenStart);
     551              96 :                     pszNewToken[pszCur - pszNewTokenStart] = 0;
     552              96 :                     OGRPGTokenizeStringListUnescapeToken(pszNewToken);
     553              96 :                     papszTokens = CSLAddString(papszTokens, pszNewToken);
     554              96 :                     CPLFree(pszNewToken);
     555                 :                 }
     556              96 :                 pszNewTokenStart = pszCur + 1;
     557                 :             }
     558             320 :             else if (pszNewTokenStart == NULL)
     559              96 :                 pszNewTokenStart = pszCur;
     560                 :         }
     561             416 :         pszCur++;
     562                 :     }
     563                 : 
     564               0 :     CPLError(CE_Warning, CPLE_AppDefined, "Incorrect string list : %s", pszText);
     565               0 :     return papszTokens;
     566                 : }
     567                 : 
     568                 : /************************************************************************/
     569                 : /*                          RecordToFeature()                           */
     570                 : /*                                                                      */
     571                 : /*      Convert the indicated record of the current result set into     */
     572                 : /*      a feature.                                                      */
     573                 : /************************************************************************/
     574                 : 
     575            7262 : OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
     576                 : 
     577                 : {
     578                 : /* -------------------------------------------------------------------- */
     579                 : /*      Create a feature from the current result.                       */
     580                 : /* -------------------------------------------------------------------- */
     581                 :     int         iField;
     582            7262 :     OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
     583                 : 
     584            7262 :     poFeature->SetFID( iNextShapeId );
     585            7262 :     m_nFeaturesRead++;
     586                 : 
     587                 : /* ==================================================================== */
     588                 : /*      Transfer all result fields we can.                              */
     589                 : /* ==================================================================== */
     590           37248 :     for( iField = 0;
     591                 :          iField < PQnfields(hCursorResult);
     592                 :          iField++ )
     593                 :     {
     594                 :         int     iOGRField;
     595                 : 
     596                 : #if !defined(PG_PRE74)
     597           29986 :         int nTypeOID = PQftype(hCursorResult, iField);
     598                 : #endif
     599           29986 :         const char* pszFieldName = PQfname(hCursorResult,iField);
     600                 : 
     601                 : /* -------------------------------------------------------------------- */
     602                 : /*      Handle FID.                                                     */
     603                 : /* -------------------------------------------------------------------- */
     604           29986 :         if( bHasFid && EQUAL(pszFieldName,pszFIDColumn) )
     605                 :         {
     606                 : #if !defined(PG_PRE74)
     607            7058 :             if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data representation
     608                 :             {
     609               0 :                 if ( nTypeOID == INT4OID)
     610                 :                 {
     611                 :                     int nVal;
     612               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(int));
     613               0 :                     memcpy( &nVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(int) );
     614               0 :                     CPL_MSBPTR32(&nVal);
     615               0 :                     poFeature->SetFID( nVal );
     616                 :                 }
     617                 :                 else
     618                 :                 {
     619               0 :                     CPLDebug("PG", "FID. Unhandled OID %d.", nTypeOID );
     620               0 :                     continue;
     621                 :                 }
     622                 :             }
     623                 :             else
     624                 : #endif /* notdef PG_PRE74 */
     625                 :             {
     626            7058 :                 char* pabyData = PQgetvalue(hCursorResult,iRecord,iField);
     627                 :                 /* ogr_pg_20 may crash if PostGIS is unavailable and we don't test pabyData */
     628            7058 :                 if (pabyData)
     629            7058 :                     poFeature->SetFID( atoi(pabyData) );
     630                 :                 else
     631               0 :                     continue;
     632                 :             }
     633                 :         }
     634                 : 
     635                 : /* -------------------------------------------------------------------- */
     636                 : /*      Handle PostGIS geometry                                         */
     637                 : /* -------------------------------------------------------------------- */
     638                 : 
     639           40918 :         if( bHasPostGISGeometry || bHasPostGISGeography )
     640                 :         {
     641           14764 :             if ( !poDS->bUseBinaryCursor &&
     642                 :                  EQUAL(pszFieldName,"BinaryBase64") )
     643                 :             {
     644                 :                 GByte* pabyData = (GByte*)PQgetvalue( hCursorResult,
     645               0 :                                                         iRecord, iField);
     646                 : 
     647               0 :                 int nLength = PQgetlength(hCursorResult, iRecord, iField);
     648                 : 
     649                 :                 /* No geometry */
     650               0 :                 if (nLength == 0)
     651               0 :                     continue;
     652                 : 
     653               0 :                 nLength = CPLBase64DecodeInPlace(pabyData);
     654               0 :                 OGRGeometry * poGeom = NULL;
     655               0 :                 OGRGeometryFactory::createFromWkb( pabyData, NULL, &poGeom, nLength );
     656                 : 
     657               0 :                 if( poGeom != NULL )
     658                 :                 {
     659               0 :                     poGeom->assignSpatialReference( poSRS );
     660               0 :                     poFeature->SetGeometryDirectly( poGeom );
     661                 :                 }
     662                 : 
     663               0 :                 continue;
     664                 :             }
     665           14764 :             else if ( EQUAL(pszFieldName,"ST_AsBinary") ||
     666                 :                  EQUAL(pszFieldName,"AsBinary") )
     667                 :             {
     668                 :                 GByte* pabyVal = (GByte*) PQgetvalue( hCursorResult,
     669               2 :                                              iRecord, iField);
     670               2 :                 const char* pszVal = (const char*) pabyVal;
     671                 : 
     672               2 :                 int nLength = PQgetlength(hCursorResult, iRecord, iField);
     673                 : 
     674                 :                 /* No geometry */
     675               2 :                 if (nLength == 0)
     676               0 :                     continue;
     677                 :                     
     678               2 :                 OGRGeometry * poGeom = NULL;
     679               4 :                 if( !poDS->bUseBinaryCursor && nLength >= 4 &&
     680                 :                     /* escaped byea data */
     681                 :                     (strncmp(pszVal, "\\000",4) == 0 || strncmp(pszVal, "\\001",4) == 0 ||
     682                 :                     /* hex bytea data (PostgreSQL >= 9.0) */
     683                 :                      strncmp(pszVal, "\\x00",4) == 0 || strncmp(pszVal, "\\x01",4) == 0) )
     684                 :                 {
     685               2 :                     poGeom = BYTEAToGeometry(pszVal);
     686                 :                 }
     687                 :                 else
     688               0 :                     OGRGeometryFactory::createFromWkb( pabyVal, NULL, &poGeom, nLength );
     689                 :                 
     690               2 :                 if( poGeom != NULL )
     691                 :                 {
     692               2 :                     poGeom->assignSpatialReference( poSRS );
     693               2 :                     poFeature->SetGeometryDirectly( poGeom );
     694                 :                 }
     695                 : 
     696               2 :                 continue;
     697                 :             }
     698           14762 :             else if ( !poDS->bUseBinaryCursor &&
     699                 :                       EQUAL(pszFieldName,"EWKBBase64") )
     700                 :             {
     701                 :                 GByte* pabyData = (GByte*)PQgetvalue( hCursorResult,
     702               2 :                                                         iRecord, iField);
     703                 : 
     704               2 :                 int nLength = PQgetlength(hCursorResult, iRecord, iField);
     705                 : 
     706                 :                 /* No geometry */
     707               2 :                 if (nLength == 0)
     708               0 :                     continue;
     709                 : 
     710               2 :                 nLength = CPLBase64DecodeInPlace(pabyData);
     711               2 :                 OGRGeometry * poGeom = EWKBToGeometry(pabyData, nLength);
     712                 : 
     713               2 :                 if( poGeom != NULL )
     714                 :                 {
     715               2 :                     poGeom->assignSpatialReference( poSRS );
     716               2 :                     poFeature->SetGeometryDirectly( poGeom );
     717                 :                 }
     718                 : 
     719               2 :                 continue;
     720                 :             }
     721           14760 :             else if ( (poDS->bUseBinaryCursor &&
     722                 :                        (EQUAL(pszFieldName,pszGeomColumn))) ||
     723                 :                       EQUAL(pszFieldName,"ST_AsEWKB") ||
     724                 :                       EQUAL(pszFieldName,"AsEWKB") )
     725                 :             {
     726                 :                 /* Handle HEX result or EWKB binary cursor result */
     727                 :                 char * pabyData = PQgetvalue( hCursorResult,
     728               6 :                                                         iRecord, iField);
     729                 : 
     730               6 :                 int nLength = PQgetlength(hCursorResult, iRecord, iField);
     731                 : 
     732                 :                 /* No geometry */
     733               6 :                 if (nLength == 0)
     734               0 :                     continue;
     735                 : 
     736                 :                 OGRGeometry * poGeom;
     737                 : 
     738               8 :                 if( !poDS->bUseBinaryCursor &&
     739                 :                     (strncmp(pabyData, "\\x00",4) == 0 || strncmp(pabyData, "\\x01",4) == 0 ||
     740                 :                      strncmp(pabyData, "\\000",4) == 0 || strncmp(pabyData, "\\001",4) == 0) )
     741                 :                 {
     742               2 :                     GByte* pabyEWKB = BYTEAToGByteArray(pabyData, &nLength);
     743               2 :                     poGeom = EWKBToGeometry(pabyEWKB, nLength);
     744               2 :                     CPLFree(pabyEWKB);
     745                 :                 }
     746               8 :                 else if( nLength >= 2 && (EQUALN(pabyData,"00",2) || EQUALN(pabyData,"01",2)) )
     747                 :                 {
     748               4 :                     poGeom = HEXToGeometry(pabyData);
     749                 :                 }
     750                 :                 else
     751                 :                 {
     752               0 :                     poGeom = EWKBToGeometry((GByte*)pabyData, nLength);
     753                 :                 }
     754                 : 
     755               6 :                 if( poGeom != NULL )
     756                 :                 {
     757               6 :                     poGeom->assignSpatialReference( poSRS );
     758               6 :                     poFeature->SetGeometryDirectly( poGeom );
     759                 :                 }
     760                 : 
     761               6 :                 continue;
     762                 :             }
     763           14754 :             else if (EQUAL(pszFieldName,pszGeomColumn) ||
     764                 :                      EQUAL(pszFieldName,"asEWKT") ||
     765                 :                      EQUAL(pszFieldName,"asText") ||
     766                 :                      EQUAL(pszFieldName,"ST_AsEWKT") ||
     767                 :                      EQUAL(pszFieldName,"ST_AsText") )
     768                 :             {
     769                 :                 /* Handle WKT */
     770                 :                 char        *pszWKT;
     771                 :                 char        *pszPostSRID;
     772            3822 :                 OGRGeometry *poGeometry = NULL;
     773                 : 
     774            3822 :                 pszWKT = PQgetvalue( hCursorResult, iRecord, iField );
     775            3822 :                 pszPostSRID = pszWKT;
     776                 : 
     777                 :                 // optionally strip off PostGIS SRID identifier.  This
     778                 :                 // happens if we got a raw geometry field.
     779            3822 :                 if( EQUALN(pszPostSRID,"SRID=",5) )
     780                 :                 {
     781               0 :                     while( *pszPostSRID != '\0' && *pszPostSRID != ';' )
     782               0 :                         pszPostSRID++;
     783               0 :                     if( *pszPostSRID == ';' )
     784               0 :                         pszPostSRID++;
     785                 :                 }
     786                 : 
     787            4430 :                 if( EQUALN(pszPostSRID,"00",2) || EQUALN(pszPostSRID,"01",2) )
     788                 :                 {
     789             608 :                     poGeometry = HEXToGeometry( pszWKT );
     790                 :                 }
     791                 :                 else
     792                 :                     OGRGeometryFactory::createFromWkt( &pszPostSRID, NULL,
     793            3214 :                                                     &poGeometry );
     794            3822 :                 if( poGeometry != NULL )
     795                 :                 {
     796             610 :                     poGeometry->assignSpatialReference( poSRS );
     797             610 :                     poFeature->SetGeometryDirectly( poGeometry );
     798                 :                 }
     799                 : 
     800            3822 :                 continue;
     801                 :             }
     802                 :         }
     803                 : /* -------------------------------------------------------------------- */
     804                 : /*      Handle raw binary geometry ... this hasn't been tested in a     */
     805                 : /*      while.                                                          */
     806                 : /* -------------------------------------------------------------------- */
     807           15222 :         else if( EQUAL(pszFieldName,"WKB_GEOMETRY") )
     808                 :         {
     809            3248 :             OGRGeometry *poGeometry = NULL;
     810            3248 :             GByte* pabyData = (GByte*) PQgetvalue( hCursorResult, iRecord, iField);
     811                 : 
     812            3248 :             if( bWkbAsOid )
     813                 :             {
     814                 :                 poGeometry =
     815               0 :                     OIDToGeometry( (Oid) atoi((const char*)pabyData) );
     816                 :             }
     817                 :             else
     818                 :             {
     819            3248 :                 if (poDS->bUseBinaryCursor
     820                 : #if !defined(PG_PRE74)
     821                 :                     && PQfformat( hCursorResult, iField ) == 1 
     822                 : #endif
     823                 :                    )
     824                 :                 {
     825               0 :                     int nLength = PQgetlength(hCursorResult, iRecord, iField);
     826               0 :                     poGeometry = EWKBToGeometry(pabyData, nLength);
     827                 :                 }
     828            3248 :                 if (poGeometry == NULL)
     829                 :                 {
     830            3248 :                     poGeometry = BYTEAToGeometry( (const char*)pabyData );
     831                 :                 }
     832                 :             }
     833                 : 
     834            3248 :             if( poGeometry != NULL )
     835                 :             {
     836             924 :                 poGeometry->assignSpatialReference( poSRS );
     837             924 :                 poFeature->SetGeometryDirectly( poGeometry );
     838                 :             }
     839                 : 
     840            3248 :             continue;
     841                 :         }
     842                 : 
     843                 : /* -------------------------------------------------------------------- */
     844                 : /*      Transfer regular data fields.                                   */
     845                 : /* -------------------------------------------------------------------- */
     846           22906 :         iOGRField = panMapFieldNameToIndex[iField];
     847                 : 
     848           22906 :         if( iOGRField < 0 )
     849            7058 :             continue;
     850                 : 
     851           15848 :         if( PQgetisnull( hCursorResult, iRecord, iField ) )
     852            4702 :             continue;
     853                 : 
     854                 :         OGRFieldType eOGRType = 
     855           11146 :             poFeatureDefn->GetFieldDefn(iOGRField)->GetType();
     856                 : 
     857           11146 :         if( eOGRType == OFTIntegerList)
     858                 :         {
     859                 :             int *panList, nCount, i;
     860                 : 
     861                 : #if !defined(PG_PRE74)
     862              32 :             if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data representation
     863                 :             {
     864               0 :                 if (nTypeOID == INT4ARRAYOID)
     865                 :                 {
     866               0 :                     char * pData = PQgetvalue( hCursorResult, iRecord, iField );
     867                 : 
     868                 :                     // goto number of array elements
     869               0 :                     pData += 3 * sizeof(int);
     870               0 :                     memcpy( &nCount, pData, sizeof(int) );
     871               0 :                     CPL_MSBPTR32( &nCount );
     872                 : 
     873               0 :                     panList = (int *) CPLCalloc(sizeof(int),nCount);
     874                 : 
     875                 :                     // goto first array element
     876               0 :                     pData += 2 * sizeof(int);
     877                 : 
     878               0 :                     for( i = 0; i < nCount; i++ )
     879                 :                     {
     880                 :                         // get element size
     881               0 :                         int nSize = *(int *)(pData);
     882               0 :                         CPL_MSBPTR32( &nSize );
     883                 : 
     884               0 :                         CPLAssert( nSize == sizeof(int) );
     885                 : 
     886               0 :                         pData += sizeof(int);
     887                 : 
     888               0 :                         memcpy( &panList[i], pData, nSize );
     889               0 :                         CPL_MSBPTR32(&panList[i]);
     890                 : 
     891               0 :                         pData += nSize;
     892                 :                     }
     893                 :                 }
     894                 :                 else
     895                 :                 {
     896               0 :                     CPLDebug("PG", "Field %d: Incompatible OID (%d) with OFTIntegerList.", iOGRField, nTypeOID );
     897               0 :                     continue;
     898                 :                 }
     899                 :             }
     900                 :             else
     901                 : #endif /* notdef PG_PRE74 */
     902                 :             {
     903                 :                 char **papszTokens;
     904                 :                 papszTokens = CSLTokenizeStringComplex(
     905                 :                     PQgetvalue( hCursorResult, iRecord, iField ),
     906              32 :                     "{,}", FALSE, FALSE );
     907                 : 
     908              32 :                 nCount = CSLCount(papszTokens);
     909              32 :                 panList = (int *) CPLCalloc(sizeof(int),nCount);
     910                 : 
     911              96 :                 for( i = 0; i < nCount; i++ )
     912              64 :                     panList[i] = atoi(papszTokens[i]);
     913              32 :                 CSLDestroy( papszTokens );
     914                 :             }
     915              32 :             poFeature->SetField( iOGRField, nCount, panList );
     916              32 :             CPLFree( panList );
     917                 :         }
     918                 : 
     919           11114 :         else if( eOGRType == OFTRealList )
     920                 :         {
     921                 :             int nCount, i;
     922                 :             double *padfList;
     923                 : 
     924                 : #if !defined(PG_PRE74)
     925             432 :             if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data representation
     926                 :             {
     927               0 :                 if (nTypeOID == FLOAT8ARRAYOID || nTypeOID == FLOAT4ARRAYOID)
     928                 :                 {
     929               0 :                     char * pData = PQgetvalue( hCursorResult, iRecord, iField );
     930                 : 
     931                 :                     // goto number of array elements
     932               0 :                     pData += 3 * sizeof(int);
     933               0 :                     memcpy( &nCount, pData, sizeof(int) );
     934               0 :                     CPL_MSBPTR32( &nCount );
     935                 : 
     936               0 :                     padfList = (double *) CPLCalloc(sizeof(double),nCount);
     937                 : 
     938                 :                     // goto first array element
     939               0 :                     pData += 2 * sizeof(int);
     940                 : 
     941               0 :                     for( i = 0; i < nCount; i++ )
     942                 :                     {
     943                 :                         // get element size
     944               0 :                         int nSize = *(int *)(pData);
     945               0 :                         CPL_MSBPTR32( &nSize );
     946                 : 
     947               0 :                         pData += sizeof(int);
     948                 : 
     949               0 :                         if (nTypeOID == FLOAT8ARRAYOID)
     950                 :                         {
     951               0 :                             CPLAssert( nSize == sizeof(double) );
     952                 : 
     953               0 :                             memcpy( &padfList[i], pData, nSize );
     954               0 :                             CPL_MSBPTR64(&padfList[i]);
     955                 :                         }
     956                 :                         else
     957                 :                         {
     958                 :                             float fVal;
     959               0 :                             CPLAssert( nSize == sizeof(float) );
     960                 : 
     961               0 :                             memcpy( &fVal, pData, nSize );
     962               0 :                             CPL_MSBPTR32(&fVal);
     963                 : 
     964               0 :                             padfList[i] = fVal;
     965                 :                         }
     966                 : 
     967               0 :                         pData += nSize;
     968                 :                     }
     969                 :                 }
     970                 :                 else
     971                 :                 {
     972               0 :                     CPLDebug("PG", "Field %d: Incompatible OID (%d) with OFTRealList.", iOGRField, nTypeOID );
     973               0 :                     continue;
     974                 :                 }
     975                 :             }
     976                 :             else
     977                 : #endif /* notdef PG_PRE74 */
     978                 :             {
     979                 :                 char **papszTokens;
     980                 :                 papszTokens = CSLTokenizeStringComplex(
     981                 :                     PQgetvalue( hCursorResult, iRecord, iField ),
     982             432 :                     "{,}", FALSE, FALSE );
     983                 : 
     984             432 :                 nCount = CSLCount(papszTokens);
     985             432 :                 padfList = (double *) CPLCalloc(sizeof(double),nCount);
     986                 : 
     987            1296 :                 for( i = 0; i < nCount; i++ )
     988             864 :                     padfList[i] = CPLAtof(papszTokens[i]);
     989             432 :                 CSLDestroy( papszTokens );
     990                 :             }
     991                 : 
     992             432 :             poFeature->SetField( iOGRField, nCount, padfList );
     993             432 :             CPLFree( padfList );
     994                 :         }
     995                 : 
     996           10682 :         else if( eOGRType == OFTStringList )
     997                 :         {
     998              96 :             char **papszTokens = 0;
     999                 : 
    1000                 : #if !defined(PG_PRE74)
    1001              96 :             if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data representation
    1002                 :             {
    1003               0 :                 char * pData = PQgetvalue( hCursorResult, iRecord, iField );
    1004                 :                 int nCount, i;
    1005                 : 
    1006                 :                 // goto number of array elements
    1007               0 :                 pData += 3 * sizeof(int);
    1008               0 :                 memcpy( &nCount, pData, sizeof(int) );
    1009               0 :                 CPL_MSBPTR32( &nCount );
    1010                 : 
    1011                 :                 // goto first array element
    1012               0 :                 pData += 2 * sizeof(int);
    1013                 : 
    1014               0 :                 for( i = 0; i < nCount; i++ )
    1015                 :                 {
    1016                 :                     // get element size
    1017               0 :                     int nSize = *(int *)(pData);
    1018               0 :                     CPL_MSBPTR32( &nSize );
    1019                 : 
    1020               0 :                     pData += sizeof(int);
    1021                 : 
    1022               0 :                     if (nSize <= 0)
    1023               0 :                         papszTokens = CSLAddString(papszTokens, "");
    1024                 :                     else
    1025                 :                     {
    1026               0 :                         if (pData[nSize] == '\0')
    1027               0 :                             papszTokens = CSLAddString(papszTokens, pData);
    1028                 :                         else
    1029                 :                         {
    1030               0 :                             char* pszToken = (char*) CPLMalloc(nSize + 1);
    1031               0 :                             memcpy(pszToken, pData, nSize);
    1032               0 :                             pszToken[nSize] = '\0';
    1033               0 :                             papszTokens = CSLAddString(papszTokens, pszToken);
    1034               0 :                             CPLFree(pszToken);
    1035                 :                         }
    1036                 : 
    1037               0 :                         pData += nSize;
    1038                 :                     }
    1039                 :                 }
    1040                 :             }
    1041                 :             else
    1042                 : #endif /* notdef PG_PRE74 */
    1043                 :             {
    1044                 :                 papszTokens =
    1045              96 :                         OGRPGTokenizeStringListFromText(PQgetvalue(hCursorResult, iRecord, iField ));
    1046                 :             }
    1047                 : 
    1048              96 :             if ( papszTokens )
    1049                 :             {
    1050              96 :                 poFeature->SetField( iOGRField, papszTokens );
    1051              96 :                 CSLDestroy( papszTokens );
    1052                 :             }
    1053                 :         }
    1054                 : 
    1055           10798 :         else if( eOGRType == OFTDate 
    1056                 :                  || eOGRType == OFTTime 
    1057                 :                  || eOGRType == OFTDateTime )
    1058                 :         {
    1059                 : #if !defined(PG_PRE74)
    1060             212 :             if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data
    1061                 :             {
    1062               0 :                 if ( nTypeOID == DATEOID )
    1063                 :                 {
    1064                 :                     int nVal, nYear, nMonth, nDay;
    1065               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(int));
    1066               0 :                     memcpy( &nVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(int) );
    1067               0 :                     CPL_MSBPTR32(&nVal);
    1068               0 :                     OGRPGj2date(nVal + POSTGRES_EPOCH_JDATE, &nYear, &nMonth, &nDay);
    1069               0 :                     poFeature->SetField( iOGRField, nYear, nMonth, nDay);
    1070                 :                 }
    1071               0 :                 else if ( nTypeOID == TIMEOID )
    1072                 :                 {
    1073                 :                     int nHour, nMinute, nSecond;
    1074                 :                     char szTime[32];
    1075                 :                     double dfsec;
    1076               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == 8);
    1077               0 :                     if (poDS->bBinaryTimeFormatIsInt8)
    1078                 :                     {
    1079                 :                         unsigned int nVal[2];
    1080                 :                         GIntBig llVal;
    1081               0 :                         memcpy( nVal, PQgetvalue( hCursorResult, iRecord, iField ), 8 );
    1082               0 :                         CPL_MSBPTR32(&nVal[0]);
    1083               0 :                         CPL_MSBPTR32(&nVal[1]);
    1084               0 :                         llVal = (GIntBig) ((((GUIntBig)nVal[0]) << 32) | nVal[1]);
    1085               0 :                         OGRPGdt2timeInt8(llVal, &nHour, &nMinute, &nSecond, &dfsec);
    1086                 :                     }
    1087                 :                     else
    1088                 :                     {
    1089                 :                         double dfVal;
    1090               0 :                         memcpy( &dfVal, PQgetvalue( hCursorResult, iRecord, iField ), 8 );
    1091               0 :                         CPL_MSBPTR64(&dfVal);
    1092               0 :                         OGRPGdt2timeFloat8(dfVal, &nHour, &nMinute, &nSecond, &dfsec);
    1093                 :                     }
    1094               0 :                     sprintf(szTime, "%02d:%02d:%02d", nHour, nMinute, nSecond);
    1095               0 :                     poFeature->SetField( iOGRField, szTime);
    1096                 :                 }
    1097               0 :                 else if ( nTypeOID == TIMESTAMPOID || nTypeOID == TIMESTAMPTZOID )
    1098                 :                 {
    1099                 :                     unsigned int nVal[2];
    1100                 :                     GIntBig llVal;
    1101                 :                     int nYear, nMonth, nDay, nHour, nMinute, nSecond;
    1102               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == 8);
    1103               0 :                     memcpy( nVal, PQgetvalue( hCursorResult, iRecord, iField ), 8 );
    1104               0 :                     CPL_MSBPTR32(&nVal[0]);
    1105               0 :                     CPL_MSBPTR32(&nVal[1]);
    1106               0 :                     llVal = (GIntBig) ((((GUIntBig)nVal[0]) << 32) | nVal[1]);
    1107               0 :                     if (OGRPGTimeStamp2DMYHMS(llVal, &nYear, &nMonth, &nDay, &nHour, &nMinute, &nSecond) == 0)
    1108               0 :                         poFeature->SetField( iOGRField, nYear, nMonth, nDay, nHour, nMinute, nSecond);
    1109                 :                 }
    1110               0 :                 else if ( nTypeOID == TEXTOID )
    1111                 :                 {
    1112                 :                     OGRField  sFieldValue;
    1113                 : 
    1114               0 :                     if( OGRParseDate( PQgetvalue( hCursorResult, iRecord, iField ),
    1115                 :                                     &sFieldValue, 0 ) )
    1116                 :                     {
    1117               0 :                         poFeature->SetField( iOGRField, &sFieldValue );
    1118                 :                     }
    1119                 :                 }
    1120                 :                 else
    1121                 :                 {
    1122               0 :                     CPLDebug( "PG", "Binary DATE format not yet implemented. OID = %d", nTypeOID );
    1123                 :                 }
    1124                 :             }
    1125                 :             else
    1126                 : #endif /* notdef PG_PRE74 */
    1127                 :             {
    1128                 :                 OGRField  sFieldValue;
    1129                 : 
    1130             212 :                 if( OGRParseDate( PQgetvalue( hCursorResult, iRecord, iField ),
    1131                 :                                   &sFieldValue, 0 ) )
    1132                 :                 {
    1133             212 :                     poFeature->SetField( iOGRField, &sFieldValue );
    1134                 :                 }
    1135                 :             }
    1136                 :         }
    1137           10374 :         else if( eOGRType == OFTBinary )
    1138                 :         {
    1139                 : #if !defined(PG_PRE74)
    1140              32 :             if ( PQfformat( hCursorResult, iField ) == 1)
    1141                 :             {
    1142               0 :                 int nLength = PQgetlength(hCursorResult, iRecord, iField);
    1143               0 :                 GByte* pabyData = (GByte*) PQgetvalue( hCursorResult, iRecord, iField );
    1144               0 :                 poFeature->SetField( iOGRField, nLength, pabyData );
    1145                 :             }
    1146                 :             else
    1147                 : #endif  /* notdef PG_PRE74 */
    1148                 :             {
    1149              32 :                 int nLength = PQgetlength(hCursorResult, iRecord, iField);
    1150              32 :                 const char* pszBytea = (const char*) PQgetvalue( hCursorResult, iRecord, iField );
    1151              32 :                 GByte* pabyData = BYTEAToGByteArray( pszBytea, &nLength );
    1152              32 :                 poFeature->SetField( iOGRField, nLength, pabyData );
    1153              32 :                 CPLFree(pabyData);
    1154                 :             }
    1155                 :         }
    1156                 :         else
    1157                 :         {
    1158                 : #if !defined(PG_PRE74)
    1159           10342 :             if ( PQfformat( hCursorResult, iField ) == 1 &&
    1160                 :                  eOGRType != OFTString ) // Binary data
    1161                 :             {
    1162               0 :                 if ( nTypeOID == BOOLOID )
    1163                 :                 {
    1164                 :                     char cVal;
    1165               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(char));
    1166               0 :                     cVal = *PQgetvalue( hCursorResult, iRecord, iField );
    1167               0 :                     poFeature->SetField( iOGRField, cVal );
    1168                 :                 }
    1169               0 :                 else if ( nTypeOID == NUMERICOID )
    1170                 :                 {
    1171                 :                     unsigned short sLen, sSign, sDscale;
    1172                 :                     short sWeight;
    1173               0 :                     char* pabyData = PQgetvalue( hCursorResult, iRecord, iField );
    1174               0 :                     memcpy( &sLen, pabyData, sizeof(short));
    1175               0 :                     pabyData += sizeof(short);
    1176               0 :                     CPL_MSBPTR16(&sLen);
    1177               0 :                     memcpy( &sWeight, pabyData, sizeof(short));
    1178               0 :                     pabyData += sizeof(short);
    1179               0 :                     CPL_MSBPTR16(&sWeight);
    1180               0 :                     memcpy( &sSign, pabyData, sizeof(short));
    1181               0 :                     pabyData += sizeof(short);
    1182               0 :                     CPL_MSBPTR16(&sSign);
    1183               0 :                     memcpy( &sDscale, pabyData, sizeof(short));
    1184               0 :                     pabyData += sizeof(short);
    1185               0 :                     CPL_MSBPTR16(&sDscale);
    1186               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == (int)((4 + sLen) * sizeof(short)));
    1187                 : 
    1188                 :                     NumericVar var;
    1189               0 :                     var.ndigits = sLen;
    1190               0 :                     var.weight = sWeight;
    1191               0 :                     var.sign = sSign;
    1192               0 :                     var.dscale = sDscale;
    1193               0 :                     var.digits = (NumericDigit*)pabyData;
    1194               0 :                     char* str = OGRPGGetStrFromBinaryNumeric(&var);
    1195               0 :                     poFeature->SetField( iOGRField, CPLAtof(str));
    1196               0 :                     CPLFree(str);
    1197                 :                 }
    1198               0 :                 else if ( nTypeOID == INT2OID )
    1199                 :                 {
    1200                 :                     short sVal;
    1201               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(short));
    1202               0 :                     memcpy( &sVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(short) );
    1203               0 :                     CPL_MSBPTR16(&sVal);
    1204               0 :                     poFeature->SetField( iOGRField, sVal );
    1205                 :                 }
    1206               0 :                 else if ( nTypeOID == INT4OID )
    1207                 :                 {
    1208                 :                     int nVal;
    1209               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(int));
    1210               0 :                     memcpy( &nVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(int) );
    1211               0 :                     CPL_MSBPTR32(&nVal);
    1212               0 :                     poFeature->SetField( iOGRField, nVal );
    1213                 :                 }
    1214               0 :                 else if ( nTypeOID == INT8OID )
    1215                 :                 {
    1216                 :                     unsigned int nVal[2];
    1217                 :                     GIntBig llVal;
    1218               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == 8);
    1219               0 :                     memcpy( nVal, PQgetvalue( hCursorResult, iRecord, iField ), 8 );
    1220               0 :                     CPL_MSBPTR32(&nVal[0]);
    1221               0 :                     CPL_MSBPTR32(&nVal[1]);
    1222               0 :                     llVal = (GIntBig) ((((GUIntBig)nVal[0]) << 32) | nVal[1]);
    1223                 :                     /* FIXME : 64bit -> 32bit conversion */
    1224               0 :                     poFeature->SetField( iOGRField, (int)llVal );
    1225                 :                 }
    1226               0 :                 else if ( nTypeOID == FLOAT4OID )
    1227                 :                 {
    1228                 :                     float fVal;
    1229               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(float));
    1230               0 :                     memcpy( &fVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(float) );
    1231               0 :                     CPL_MSBPTR32(&fVal);
    1232               0 :                     poFeature->SetField( iOGRField, fVal );
    1233                 :                 }
    1234               0 :                 else if ( nTypeOID == FLOAT8OID )
    1235                 :                 {
    1236                 :                     double dfVal;
    1237               0 :                     CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(double));
    1238               0 :                     memcpy( &dfVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(double) );
    1239               0 :                     CPL_MSBPTR64(&dfVal);
    1240               0 :                     poFeature->SetField( iOGRField, dfVal );
    1241                 :                 }
    1242                 :                 else
    1243                 :                 {
    1244                 :                     CPLDebug("PG", "Field %d: Incompatible OID (%d) with %s.", iOGRField, nTypeOID,
    1245               0 :                              OGRFieldDefn::GetFieldTypeName( eOGRType ));
    1246               0 :                     continue;
    1247                 :                 }
    1248                 :             }
    1249                 :             else
    1250                 : #endif /* notdef PG_PRE74 */
    1251                 :             {
    1252           10342 :                 if ( eOGRType == OFTInteger &&
    1253                 :                      poFeatureDefn->GetFieldDefn(iOGRField)->GetWidth() == 1)
    1254                 :                 {
    1255              32 :                     char* pabyData = PQgetvalue( hCursorResult, iRecord, iField );
    1256              32 :                     if (EQUALN(pabyData, "T", 1))
    1257              24 :                         poFeature->SetField( iOGRField, 1);
    1258               8 :                     else if (EQUALN(pabyData, "F", 1))
    1259               0 :                         poFeature->SetField( iOGRField, 0);
    1260                 :                     else
    1261               8 :                         poFeature->SetField( iOGRField, pabyData);
    1262                 :                 }
    1263           10310 :                 else if ( eOGRType == OFTReal )
    1264                 :                 {
    1265                 :                     poFeature->SetField( iOGRField,
    1266            1476 :                                 CPLAtof(PQgetvalue( hCursorResult, iRecord, iField )) );
    1267                 :                 }
    1268                 :                 else
    1269                 :                 {
    1270                 :                     poFeature->SetField( iOGRField,
    1271            8834 :                                         PQgetvalue( hCursorResult, iRecord, iField ) );
    1272                 :                 }
    1273                 :             }
    1274                 :         }
    1275                 :     }
    1276                 : 
    1277            7262 :     return poFeature;
    1278                 : }
    1279                 : 
    1280                 : /************************************************************************/
    1281                 : /*                CreateMapFromFieldNameToIndex()                       */
    1282                 : /************************************************************************/
    1283                 : 
    1284                 : /* Evaluating GetFieldIndex() on each field of each feature can be very */
    1285                 : /* expensive if the layer has many fields (total complexity of O(n^2) where */
    1286                 : /* n is the number of fields), so it is valuable to compute the map from */
    1287                 : /* the fetched fields to the OGR field index */
    1288             524 : void OGRPGLayer::CreateMapFromFieldNameToIndex()
    1289                 : {
    1290             524 :     CPLFree(panMapFieldNameToIndex);
    1291             524 :     panMapFieldNameToIndex = NULL;
    1292             524 :     if ( PQresultStatus(hCursorResult)  == PGRES_TUPLES_OK )
    1293                 :     {
    1294                 :         panMapFieldNameToIndex =
    1295             524 :                 (int*)CPLMalloc(sizeof(int) * PQnfields(hCursorResult));
    1296            3692 :         for( int iField = 0;
    1297                 :             iField < PQnfields(hCursorResult);
    1298                 :             iField++ )
    1299                 :         {
    1300            3168 :             panMapFieldNameToIndex[iField] =
    1301            3168 :                     poFeatureDefn->GetFieldIndex(PQfname(hCursorResult,iField));
    1302                 :         }
    1303                 :     }
    1304             524 : }
    1305                 : 
    1306                 : 
    1307                 : /************************************************************************/
    1308                 : /*                     SetInitialQueryCursor()                          */
    1309                 : /************************************************************************/
    1310                 : 
    1311             406 : void OGRPGLayer::SetInitialQueryCursor()
    1312                 : {
    1313             406 :     PGconn      *hPGConn = poDS->GetPGConn();
    1314             406 :     CPLString   osCommand;
    1315                 : 
    1316             406 :     CPLAssert( pszQueryStatement != NULL );
    1317                 : 
    1318             406 :     poDS->FlushSoftTransaction();
    1319             406 :     poDS->SoftStartTransaction();
    1320                 : 
    1321             410 :     if ( poDS->bUseBinaryCursor && bCanUseBinaryCursor )
    1322                 :         osCommand.Printf( "DECLARE %s BINARY CURSOR for %s",
    1323               4 :                             pszCursorName, pszQueryStatement );
    1324                 :     else
    1325                 :         osCommand.Printf( "DECLARE %s CURSOR for %s",
    1326             402 :                             pszCursorName, pszQueryStatement );
    1327                 : 
    1328             406 :     hCursorResult = OGRPG_PQexec(hPGConn, osCommand );
    1329             406 :     if ( !hCursorResult || PQresultStatus(hCursorResult) != PGRES_COMMAND_OK )
    1330                 :     {
    1331                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1332               0 :                   "%s", PQerrorMessage( hPGConn ) );
    1333                 :     }
    1334             406 :     OGRPGClearResult( hCursorResult );
    1335                 : 
    1336             406 :     osCommand.Printf( "FETCH %d in %s", CURSOR_PAGE, pszCursorName );
    1337             406 :     hCursorResult = OGRPG_PQexec(hPGConn, osCommand );
    1338                 : 
    1339             406 :     CreateMapFromFieldNameToIndex();
    1340                 : 
    1341             406 :     nResultOffset = 0;
    1342             406 : }
    1343                 : 
    1344                 : /************************************************************************/
    1345                 : /*                         GetNextRawFeature()                          */
    1346                 : /************************************************************************/
    1347                 : 
    1348            7286 : OGRFeature *OGRPGLayer::GetNextRawFeature()
    1349                 : 
    1350                 : {
    1351            7286 :     PGconn      *hPGConn = poDS->GetPGConn();
    1352            7286 :     CPLString   osCommand;
    1353                 : 
    1354                 : /* -------------------------------------------------------------------- */
    1355                 : /*      Do we need to establish an initial query?                       */
    1356                 : /* -------------------------------------------------------------------- */
    1357            7286 :     if( iNextShapeId == 0 && hCursorResult == NULL )
    1358                 :     {
    1359             394 :         SetInitialQueryCursor();
    1360                 :     }
    1361                 : 
    1362                 : /* -------------------------------------------------------------------- */
    1363                 : /*      Are we in some sort of error condition?                         */
    1364                 : /* -------------------------------------------------------------------- */
    1365            7286 :     if( hCursorResult == NULL
    1366                 :         || PQresultStatus(hCursorResult) != PGRES_TUPLES_OK )
    1367                 :     {
    1368               0 :         CPLDebug( "PG", "PQclear() on an error condition");
    1369                 : 
    1370               0 :         OGRPGClearResult( hCursorResult );
    1371                 : 
    1372               0 :         iNextShapeId = MAX(1,iNextShapeId);
    1373               0 :         return NULL;
    1374                 :     }
    1375                 : 
    1376                 : /* -------------------------------------------------------------------- */
    1377                 : /*      Do we need to fetch more records?                               */
    1378                 : /* -------------------------------------------------------------------- */
    1379                 : 
    1380                 :     /* We test for PQntuples(hCursorResult) == 1 in the case the previous */
    1381                 :     /* request was a SetNextByIndex() */
    1382            7286 :     if( (PQntuples(hCursorResult) == 1 || PQntuples(hCursorResult) == CURSOR_PAGE) &&
    1383                 :         nResultOffset == PQntuples(hCursorResult) )
    1384                 :     {
    1385              60 :         OGRPGClearResult( hCursorResult );
    1386                 :         
    1387              60 :         osCommand.Printf( "FETCH %d in %s", CURSOR_PAGE, pszCursorName );
    1388              60 :         hCursorResult = OGRPG_PQexec(hPGConn, osCommand );
    1389                 : 
    1390              60 :         nResultOffset = 0;
    1391                 :     }
    1392                 : 
    1393                 : /* -------------------------------------------------------------------- */
    1394                 : /*      Are we out of results?  If so complete the transaction, and     */
    1395                 : /*      cleanup, but don't reset the next shapeid.                      */
    1396                 : /* -------------------------------------------------------------------- */
    1397            7286 :     if( nResultOffset == PQntuples(hCursorResult) )
    1398                 :     {
    1399             142 :         CloseCursor();
    1400                 : 
    1401             142 :         iNextShapeId = MAX(1,iNextShapeId);
    1402                 : 
    1403             142 :         return NULL;
    1404                 :     }
    1405                 : 
    1406                 : 
    1407                 : /* -------------------------------------------------------------------- */
    1408                 : /*      Create a feature from the current result.                       */
    1409                 : /* -------------------------------------------------------------------- */
    1410            7144 :     OGRFeature *poFeature = RecordToFeature( nResultOffset );
    1411                 : 
    1412            7144 :     nResultOffset++;
    1413            7144 :     iNextShapeId++;
    1414                 : 
    1415            7144 :     return poFeature;
    1416                 : }
    1417                 : 
    1418                 : /************************************************************************/
    1419                 : /*                           SetNextByIndex()                           */
    1420                 : /************************************************************************/
    1421                 : 
    1422              36 : OGRErr OGRPGLayer::SetNextByIndex( long nIndex )
    1423                 : 
    1424                 : {
    1425              36 :     GetLayerDefn();
    1426                 : 
    1427              36 :     if( !TestCapability(OLCFastSetNextByIndex) )
    1428               0 :         return OGRLayer::SetNextByIndex(nIndex);
    1429                 : 
    1430              36 :     if( nIndex == iNextShapeId)
    1431                 :     {
    1432               8 :         return OGRERR_NONE;
    1433                 :     }
    1434                 :     
    1435              28 :     if( nIndex < 0 )
    1436                 :     {
    1437               4 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid index");
    1438               4 :         return OGRERR_FAILURE;
    1439                 :     }
    1440                 :     
    1441              24 :     if( nIndex == 0 )
    1442                 :     {
    1443               0 :         ResetReading();
    1444               0 :         return OGRERR_NONE;
    1445                 :     }
    1446                 :     
    1447              24 :     PGconn      *hPGConn = poDS->GetPGConn();
    1448              24 :     CPLString   osCommand;
    1449                 :     
    1450              24 :     if (hCursorResult == NULL )
    1451                 :     {
    1452              12 :         SetInitialQueryCursor();
    1453                 :     }
    1454                 :     
    1455              24 :     OGRPGClearResult( hCursorResult );
    1456                 :     
    1457              24 :     osCommand.Printf( "FETCH ABSOLUTE %ld in %s", nIndex+1, pszCursorName );
    1458              24 :     hCursorResult = OGRPG_PQexec(hPGConn, osCommand );
    1459                 : 
    1460              24 :     if (PQresultStatus(hCursorResult) != PGRES_TUPLES_OK ||
    1461                 :         PQntuples(hCursorResult) != 1)
    1462                 :     {
    1463                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1464               4 :                   "Attempt to read feature at invalid index (%ld).", nIndex );
    1465                 : 
    1466               4 :         CloseCursor();
    1467                 : 
    1468               4 :         iNextShapeId = 0;
    1469                 : 
    1470               4 :         return OGRERR_FAILURE;
    1471                 :     }
    1472                 : 
    1473              20 :     nResultOffset = 0;
    1474              20 :     iNextShapeId = nIndex;
    1475                 :     
    1476              20 :     return OGRERR_NONE;
    1477                 : }
    1478                 : 
    1479                 : /************************************************************************/
    1480                 : /*                           HEXToGeometry()                            */
    1481                 : /************************************************************************/
    1482                 : 
    1483             612 : OGRGeometry *OGRPGLayer::HEXToGeometry( const char *pszBytea )
    1484                 : 
    1485                 : {
    1486                 :     GByte   *pabyWKB;
    1487             612 :     int     nWKBLength=0;
    1488                 :     OGRGeometry *poGeometry;
    1489                 : 
    1490             612 :     if( pszBytea == NULL )
    1491               0 :         return NULL;
    1492                 : 
    1493             612 :     pabyWKB = CPLHexToBinary(pszBytea, &nWKBLength);
    1494                 : 
    1495             612 :     poGeometry = EWKBToGeometry(pabyWKB, nWKBLength);
    1496                 : 
    1497             612 :     CPLFree(pabyWKB);
    1498                 : 
    1499             612 :     return poGeometry;
    1500                 : }
    1501                 : 
    1502                 : 
    1503                 : /************************************************************************/
    1504                 : /*                          EWKBToGeometry()                            */
    1505                 : /************************************************************************/
    1506                 : 
    1507             616 : OGRGeometry *OGRPGLayer::EWKBToGeometry( GByte *pabyWKB, int nLength )
    1508                 : 
    1509                 : {
    1510             616 :     OGRGeometry *poGeometry = NULL;
    1511             616 :     unsigned int ewkbFlags = 0;
    1512                 :     
    1513             616 :     if (nLength < 5)
    1514                 :     {
    1515                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1516               0 :                   "Invalid EWKB content : %d bytes", nLength );
    1517               0 :         return NULL;
    1518                 :     }
    1519                 : 
    1520                 : /* -------------------------------------------------------------------- */
    1521                 : /*      Detect XYZM variant of PostGIS EWKB                             */
    1522                 : /*                                                                      */
    1523                 : /*      OGR does not support parsing M coordinate,                      */
    1524                 : /*      so we return NULL geometry.                                     */
    1525                 : /* -------------------------------------------------------------------- */
    1526             616 :     memcpy(&ewkbFlags, pabyWKB+1, 4);
    1527             616 :     OGRwkbByteOrder eByteOrder = (pabyWKB[0] == 0 ? wkbXDR : wkbNDR);
    1528             616 :     if( OGR_SWAP( eByteOrder ) )
    1529               0 :         ewkbFlags= CPL_SWAP32(ewkbFlags);
    1530                 : 
    1531             616 :     if (ewkbFlags & 0x40000000)
    1532                 :     {
    1533                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1534              14 :             "Reading EWKB with 4-dimensional coordinates (XYZM) is not supported" );
    1535                 : 
    1536              14 :         return NULL;
    1537                 :     }
    1538                 : 
    1539                 : /* -------------------------------------------------------------------- */
    1540                 : /*      PostGIS EWKB format includes an  SRID, but this won't be        */
    1541                 : /*      understood by OGR, so if the SRID flag is set, we remove the    */
    1542                 : /*      SRID (bytes at offset 5 to 8).                                  */
    1543                 : /* -------------------------------------------------------------------- */
    1544            2408 :     if( nLength > 9 &&
    1545             602 :         ((pabyWKB[0] == 0 /* big endian */ && (pabyWKB[1] & 0x20) )
    1546            1204 :         || (pabyWKB[0] != 0 /* little endian */ && (pabyWKB[4] & 0x20))) )
    1547                 :     {
    1548               6 :         memmove( pabyWKB+5, pabyWKB+9, nLength-9 );
    1549               6 :         nLength -= 4;
    1550               6 :         if( pabyWKB[0] == 0 )
    1551               0 :             pabyWKB[1] &= (~0x20);
    1552                 :         else
    1553               6 :             pabyWKB[4] &= (~0x20);
    1554                 :     }
    1555                 : 
    1556                 : /* -------------------------------------------------------------------- */
    1557                 : /*      Try to ingest the geometry.                                     */
    1558                 : /* -------------------------------------------------------------------- */
    1559             602 :     OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nLength );
    1560                 : 
    1561             602 :     return poGeometry;
    1562                 : }
    1563                 : 
    1564                 : /************************************************************************/
    1565                 : /*                           GeometryToHex()                            */
    1566                 : /************************************************************************/
    1567             224 : char *OGRPGLayer::GeometryToHex( OGRGeometry * poGeometry, int nSRSId )
    1568                 : {
    1569                 :     GByte       *pabyWKB;
    1570                 :     char        *pszTextBuf;
    1571                 :     char        *pszTextBufCurrent;
    1572                 :     char        *pszHex;
    1573                 : 
    1574             224 :     int nWkbSize = poGeometry->WkbSize();
    1575             224 :     pabyWKB = (GByte *) CPLMalloc(nWkbSize);
    1576                 : 
    1577             224 :     if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
    1578                 :     {
    1579               0 :         CPLFree( pabyWKB );
    1580               0 :         return CPLStrdup("");
    1581                 :     }
    1582                 : 
    1583                 :     /* When converting to hex, each byte takes 2 hex characters.  In addition
    1584                 :        we add in 8 characters to represent the SRID integer in hex, and
    1585                 :        one for a null terminator */
    1586                 : 
    1587             224 :     int pszSize = nWkbSize*2 + 8 + 1;
    1588             224 :     pszTextBuf = (char *) CPLMalloc(pszSize);
    1589             224 :     pszTextBufCurrent = pszTextBuf;
    1590                 : 
    1591                 :     /* Convert the 1st byte, which is the endianess flag, to hex. */
    1592             224 :     pszHex = CPLBinaryToHex( 1, pabyWKB );
    1593             224 :     strcpy(pszTextBufCurrent, pszHex );
    1594             224 :     CPLFree ( pszHex );
    1595             224 :     pszTextBufCurrent += 2;
    1596                 : 
    1597                 :     /* Next, get the geom type which is bytes 2 through 5 */
    1598                 :     GUInt32 geomType;
    1599             224 :     memcpy( &geomType, pabyWKB+1, 4 );
    1600                 : 
    1601                 :     /* Now add the SRID flag if an SRID is provided */
    1602             224 :     if (nSRSId > 0)
    1603                 :     {
    1604                 :         /* Change the flag to wkbNDR (little) endianess */
    1605             126 :         GUInt32 nGSrsFlag = CPL_LSBWORD32( WKBSRIDFLAG );
    1606                 :         /* Apply the flag */
    1607             126 :         geomType = geomType | nGSrsFlag;
    1608                 :     }
    1609                 : 
    1610                 :     /* Now write the geom type which is 4 bytes */
    1611             224 :     pszHex = CPLBinaryToHex( 4, (GByte*) &geomType );
    1612             224 :     strcpy(pszTextBufCurrent, pszHex );
    1613             224 :     CPLFree ( pszHex );
    1614             224 :     pszTextBufCurrent += 8;
    1615                 : 
    1616                 :     /* Now include SRID if provided */
    1617             224 :     if (nSRSId > 0)
    1618                 :     {
    1619                 :         /* Force the srsid to wkbNDR (little) endianess */
    1620             126 :         GUInt32 nGSRSId = CPL_LSBWORD32( nSRSId );
    1621             126 :         pszHex = CPLBinaryToHex( sizeof(nGSRSId),(GByte*) &nGSRSId );
    1622             126 :         strcpy(pszTextBufCurrent, pszHex );
    1623             126 :         CPLFree ( pszHex );
    1624             126 :         pszTextBufCurrent += 8;
    1625                 :     }
    1626                 : 
    1627                 :     /* Copy the rest of the data over - subtract
    1628                 :        5 since we already copied 5 bytes above */
    1629             224 :     pszHex = CPLBinaryToHex( nWkbSize - 5, pabyWKB + 5 );
    1630             224 :     strcpy(pszTextBufCurrent, pszHex );
    1631             224 :     CPLFree ( pszHex );
    1632                 : 
    1633             224 :     CPLFree( pabyWKB );
    1634                 : 
    1635             224 :     return pszTextBuf;
    1636                 : }
    1637                 : 
    1638                 : 
    1639                 : /************************************************************************/
    1640                 : /*                        BYTEAToGByteArray()                           */
    1641                 : /************************************************************************/
    1642                 : 
    1643            3284 : GByte* OGRPGLayer::BYTEAToGByteArray( const char *pszBytea, int* pnLength )
    1644                 : {
    1645                 :     GByte* pabyData;
    1646            3284 :     int iSrc=0, iDst=0;
    1647                 : 
    1648            3284 :     if( pszBytea == NULL )
    1649                 :     {
    1650               0 :         if (pnLength) *pnLength = 0;
    1651               0 :         return NULL;
    1652                 :     }
    1653                 : 
    1654                 :     /* hex bytea data (PostgreSQL >= 9.0) */
    1655            3284 :     if (pszBytea[0] == '\\' && pszBytea[1] == 'x')
    1656               0 :         return CPLHexToBinary(pszBytea + 2, pnLength);
    1657                 : 
    1658            3284 :     pabyData = (GByte *) CPLMalloc(strlen(pszBytea));
    1659                 : 
    1660          284114 :     while( pszBytea[iSrc] != '\0' )
    1661                 :     {
    1662          277546 :         if( pszBytea[iSrc] == '\\' )
    1663                 :         {
    1664          349794 :             if( pszBytea[iSrc+1] >= '0' && pszBytea[iSrc+1] <= '9' )
    1665                 :             {
    1666          349496 :                 if (pszBytea[iSrc+2] == '\0' ||
    1667          174748 :                     pszBytea[iSrc+3] == '\0')
    1668               0 :                     break;
    1669                 : 
    1670          349496 :                 pabyData[iDst++] =
    1671          174748 :                     (pszBytea[iSrc+1] - 48) * 64
    1672          174748 :                     + (pszBytea[iSrc+2] - 48) * 8
    1673          349496 :                     + (pszBytea[iSrc+3] - 48) * 1;
    1674          174748 :                 iSrc += 4;
    1675                 :             }
    1676                 :             else
    1677                 :             {
    1678             298 :                 if (pszBytea[iSrc+1] == '\0')
    1679               0 :                     break;
    1680                 : 
    1681             298 :                 pabyData[iDst++] = pszBytea[iSrc+1];
    1682             298 :                 iSrc += 2;
    1683                 :             }
    1684                 :         }
    1685                 :         else
    1686                 :         {
    1687          102500 :             pabyData[iDst++] = pszBytea[iSrc++];
    1688                 :         }
    1689                 :     }
    1690            3284 :     if (pnLength) *pnLength = iDst;
    1691                 : 
    1692            3284 :     return pabyData;
    1693                 : }
    1694                 : 
    1695                 : 
    1696                 : /************************************************************************/
    1697                 : /*                          BYTEAToGeometry()                           */
    1698                 : /************************************************************************/
    1699                 : 
    1700            3250 : OGRGeometry *OGRPGLayer::BYTEAToGeometry( const char *pszBytea )
    1701                 : 
    1702                 : {
    1703                 :     GByte       *pabyWKB;
    1704            3250 :     int nLen=0;
    1705                 :     OGRGeometry *poGeometry;
    1706                 : 
    1707            3250 :     if( pszBytea == NULL )
    1708               0 :         return NULL;
    1709                 : 
    1710            3250 :     pabyWKB = BYTEAToGByteArray(pszBytea, &nLen);
    1711                 : 
    1712            3250 :     poGeometry = NULL;
    1713            3250 :     OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nLen );
    1714                 : 
    1715            3250 :     CPLFree( pabyWKB );
    1716            3250 :     return poGeometry;
    1717                 : }
    1718                 : 
    1719                 : 
    1720                 : /************************************************************************/
    1721                 : /*                        GByteArrayToBYTEA()                           */
    1722                 : /************************************************************************/
    1723                 : 
    1724             104 : char* OGRPGLayer::GByteArrayToBYTEA( const GByte* pabyData, int nLen)
    1725                 : {
    1726                 :     char* pszTextBuf;
    1727                 : 
    1728             104 :     pszTextBuf = (char *) CPLMalloc(nLen*5+1);
    1729                 : 
    1730             104 :     int  iSrc, iDst=0;
    1731                 : 
    1732           30418 :     for( iSrc = 0; iSrc < nLen; iSrc++ )
    1733                 :     {
    1734           60662 :         if( pabyData[iSrc] < 40 || pabyData[iSrc] > 126
    1735           11004 :             || pabyData[iSrc] == '\\' )
    1736                 :         {
    1737           19344 :             sprintf( pszTextBuf+iDst, "\\\\%03o", pabyData[iSrc] );
    1738           19344 :             iDst += 5;
    1739                 :         }
    1740                 :         else
    1741           10970 :             pszTextBuf[iDst++] = pabyData[iSrc];
    1742                 :     }
    1743             104 :     pszTextBuf[iDst] = '\0';
    1744                 : 
    1745             104 :     return pszTextBuf;
    1746                 : }
    1747                 : 
    1748                 : /************************************************************************/
    1749                 : /*                          GeometryToBYTEA()                           */
    1750                 : /************************************************************************/
    1751                 : 
    1752              96 : char *OGRPGLayer::GeometryToBYTEA( OGRGeometry * poGeometry )
    1753                 : 
    1754                 : {
    1755              96 :     int         nWkbSize = poGeometry->WkbSize();
    1756                 :     GByte       *pabyWKB;
    1757                 :     char        *pszTextBuf;
    1758                 : 
    1759              96 :     pabyWKB = (GByte *) CPLMalloc(nWkbSize);
    1760              96 :     if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
    1761                 :     {
    1762               0 :         CPLFree(pabyWKB);
    1763               0 :         return CPLStrdup("");
    1764                 :     }
    1765                 : 
    1766              96 :     pszTextBuf = GByteArrayToBYTEA( pabyWKB, nWkbSize );
    1767              96 :     CPLFree(pabyWKB);
    1768                 : 
    1769              96 :     return pszTextBuf;
    1770                 : }
    1771                 : 
    1772                 : /************************************************************************/
    1773                 : /*                          OIDToGeometry()                             */
    1774                 : /************************************************************************/
    1775                 : 
    1776               0 : OGRGeometry *OGRPGLayer::OIDToGeometry( Oid oid )
    1777                 : 
    1778                 : {
    1779               0 :     PGconn      *hPGConn = poDS->GetPGConn();
    1780                 :     GByte       *pabyWKB;
    1781                 :     int         fd, nBytes;
    1782                 :     OGRGeometry *poGeometry;
    1783                 : 
    1784                 : #define MAX_WKB 500000
    1785                 : 
    1786               0 :     if( oid == 0 )
    1787               0 :         return NULL;
    1788                 : 
    1789               0 :     fd = lo_open( hPGConn, oid, INV_READ );
    1790               0 :     if( fd < 0 )
    1791               0 :         return NULL;
    1792                 : 
    1793               0 :     pabyWKB = (GByte *) CPLMalloc(MAX_WKB);
    1794               0 :     nBytes = lo_read( hPGConn, fd, (char *) pabyWKB, MAX_WKB );
    1795               0 :     lo_close( hPGConn, fd );
    1796                 : 
    1797               0 :     poGeometry = NULL;
    1798               0 :     OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nBytes );
    1799                 : 
    1800               0 :     CPLFree( pabyWKB );
    1801                 : 
    1802               0 :     return poGeometry;
    1803                 : }
    1804                 : 
    1805                 : /************************************************************************/
    1806                 : /*                           GeometryToOID()                            */
    1807                 : /************************************************************************/
    1808                 : 
    1809               0 : Oid OGRPGLayer::GeometryToOID( OGRGeometry * poGeometry )
    1810                 : 
    1811                 : {
    1812               0 :     PGconn      *hPGConn = poDS->GetPGConn();
    1813               0 :     int         nWkbSize = poGeometry->WkbSize();
    1814                 :     GByte       *pabyWKB;
    1815                 :     Oid         oid;
    1816                 :     int         fd, nBytesWritten;
    1817                 : 
    1818               0 :     pabyWKB = (GByte *) CPLMalloc(nWkbSize);
    1819               0 :     if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
    1820               0 :         return 0;
    1821                 : 
    1822               0 :     oid = lo_creat( hPGConn, INV_READ|INV_WRITE );
    1823                 : 
    1824               0 :     fd = lo_open( hPGConn, oid, INV_WRITE );
    1825               0 :     nBytesWritten = lo_write( hPGConn, fd, (char *) pabyWKB, nWkbSize );
    1826               0 :     lo_close( hPGConn, fd );
    1827                 : 
    1828               0 :     if( nBytesWritten != nWkbSize )
    1829                 :     {
    1830                 :         CPLDebug( "PG",
    1831                 :                   "Only wrote %d bytes of %d intended for (fd=%d,oid=%d).\n",
    1832               0 :                   nBytesWritten, nWkbSize, fd, oid );
    1833                 :     }
    1834                 : 
    1835               0 :     CPLFree( pabyWKB );
    1836                 : 
    1837               0 :     return oid;
    1838                 : }
    1839                 : 
    1840                 : /************************************************************************/
    1841                 : /*                          StartTransaction()                          */
    1842                 : /************************************************************************/
    1843                 : 
    1844             100 : OGRErr OGRPGLayer::StartTransaction()
    1845                 : 
    1846                 : {
    1847             100 :     return poDS->SoftStartTransaction();
    1848                 : }
    1849                 : 
    1850                 : /************************************************************************/
    1851                 : /*                         CommitTransaction()                          */
    1852                 : /************************************************************************/
    1853                 : 
    1854              84 : OGRErr OGRPGLayer::CommitTransaction()
    1855                 : 
    1856                 : {
    1857              84 :     return poDS->SoftCommit();
    1858                 : }
    1859                 : 
    1860                 : /************************************************************************/
    1861                 : /*                        RollbackTransaction()                         */
    1862                 : /************************************************************************/
    1863                 : 
    1864              16 : OGRErr OGRPGLayer::RollbackTransaction()
    1865                 : 
    1866                 : {
    1867              16 :     return poDS->SoftRollback();
    1868                 : }
    1869                 : 
    1870                 : /************************************************************************/
    1871                 : /*                           GetSpatialRef()                            */
    1872                 : /************************************************************************/
    1873                 : 
    1874              90 : OGRSpatialReference *OGRPGLayer::GetSpatialRef()
    1875                 : 
    1876                 : {
    1877              90 :     if (nSRSId == UNDETERMINED_SRID)
    1878              66 :         GetLayerDefn();
    1879                 : 
    1880              90 :     if( poSRS == NULL && nSRSId > 0 )
    1881                 :     {
    1882               8 :         poSRS = poDS->FetchSRS( nSRSId );
    1883               8 :         if( poSRS != NULL )
    1884               8 :             poSRS->Reference();
    1885                 :     }
    1886                 : 
    1887              90 :     return poSRS;
    1888                 : }
    1889                 : 
    1890                 : /************************************************************************/
    1891                 : /*                            GetFIDColumn()                            */
    1892                 : /************************************************************************/
    1893                 : 
    1894              12 : const char *OGRPGLayer::GetFIDColumn() 
    1895                 : 
    1896                 : {
    1897              12 :     GetLayerDefn();
    1898                 : 
    1899              12 :     if( pszFIDColumn != NULL )
    1900               8 :         return pszFIDColumn;
    1901                 :     else
    1902               4 :         return "";
    1903                 : }
    1904                 : 
    1905                 : /************************************************************************/
    1906                 : /*                         GetGeometryColumn()                          */
    1907                 : /************************************************************************/
    1908                 : 
    1909              12 : const char *OGRPGLayer::GetGeometryColumn() 
    1910                 : 
    1911                 : {
    1912              12 :     GetLayerDefn();
    1913                 : 
    1914              12 :     if( pszGeomColumn != NULL )
    1915              12 :         return pszGeomColumn;
    1916                 :     else
    1917               0 :         return "";
    1918                 : }
    1919                 : 
    1920                 : /************************************************************************/
    1921                 : /*                             GetExtent()                              */
    1922                 : /************************************************************************/
    1923                 : 
    1924              24 : OGRErr OGRPGLayer::RunGetExtentRequest( OGREnvelope *psExtent, int bForce,
    1925                 :                                         CPLString osCommand)
    1926                 : {
    1927              24 :     if ( psExtent == NULL )
    1928               0 :         return OGRERR_FAILURE;
    1929                 : 
    1930              24 :     if ( TestCapability(OLCFastGetExtent) || bHasPostGISGeography )
    1931                 :     {
    1932              12 :         PGconn      *hPGConn = poDS->GetPGConn();
    1933              12 :         PGresult    *hResult = NULL;
    1934                 : 
    1935              12 :         hResult = OGRPG_PQexec( hPGConn, osCommand );
    1936              12 :         if( ! hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK || PQgetisnull(hResult,0,0) )
    1937                 :         {
    1938               0 :             OGRPGClearResult( hResult );
    1939               0 :             CPLDebug("PG","Unable to get extent by PostGIS. Using standard OGRLayer method.");
    1940               0 :             return OGRPGLayer::GetExtent( psExtent, bForce );
    1941                 :         }
    1942                 : 
    1943              12 :         char * pszBox = PQgetvalue(hResult,0,0);
    1944                 :         char * ptr, *ptrEndParenthesis;
    1945                 :         char szVals[64*6+6];
    1946                 : 
    1947              12 :         ptr = strchr(pszBox, '(');
    1948              12 :         if (ptr)
    1949              12 :             ptr ++;
    1950              12 :         if (ptr == NULL ||
    1951                 :             (ptrEndParenthesis = strchr(ptr, ')')) == NULL ||
    1952                 :             ptrEndParenthesis - ptr > (int)(sizeof(szVals) - 1))
    1953                 :         {
    1954                 :             CPLError( CE_Failure, CPLE_IllegalArg,
    1955               0 :                       "Bad extent representation: '%s'", pszBox);
    1956                 : 
    1957               0 :             OGRPGClearResult( hResult );
    1958               0 :             return OGRERR_FAILURE;
    1959                 :         }
    1960                 : 
    1961              12 :         strncpy(szVals,ptr,ptrEndParenthesis - ptr);
    1962              12 :         szVals[ptrEndParenthesis - ptr] = '\0';
    1963                 : 
    1964              12 :         char ** papszTokens = CSLTokenizeString2(szVals," ,",CSLT_HONOURSTRINGS);
    1965              12 :         int nTokenCnt = poDS->sPostGISVersion.nMajor >= 1 ? 4 : 6;
    1966                 : 
    1967              12 :         if ( CSLCount(papszTokens) != nTokenCnt )
    1968                 :         {
    1969                 :             CPLError( CE_Failure, CPLE_IllegalArg,
    1970               0 :                       "Bad extent representation: '%s'", pszBox);
    1971               0 :             CSLDestroy(papszTokens);
    1972                 : 
    1973               0 :             OGRPGClearResult( hResult );
    1974               0 :             return OGRERR_FAILURE;
    1975                 :         }
    1976                 : 
    1977                 :         // Take X,Y coords
    1978                 :         // For PostGis ver >= 1.0.0 -> Tokens: X1 Y1 X2 Y2 (nTokenCnt = 4)
    1979                 :         // For PostGIS ver < 1.0.0 -> Tokens: X1 Y1 Z1 X2 Y2 Z2 (nTokenCnt = 6)
    1980                 :         // =>   X2 index calculated as nTokenCnt/2
    1981                 :         //      Y2 index caluclated as nTokenCnt/2+1
    1982                 :         
    1983              12 :         psExtent->MinX = CPLAtof( papszTokens[0] );
    1984              12 :         psExtent->MinY = CPLAtof( papszTokens[1] );
    1985              12 :         psExtent->MaxX = CPLAtof( papszTokens[nTokenCnt/2] );
    1986              12 :         psExtent->MaxY = CPLAtof( papszTokens[nTokenCnt/2+1] );
    1987                 : 
    1988              12 :         CSLDestroy(papszTokens);
    1989              12 :         OGRPGClearResult( hResult );
    1990                 : 
    1991              12 :         return OGRERR_NONE;
    1992                 :     }
    1993                 : 
    1994              12 :     return OGRLayer::GetExtent( psExtent, bForce );
    1995                 : }
    1996                 : 
    1997                 : /************************************************************************/
    1998                 : /*                         GetLayerDefn()                              */
    1999                 : /************************************************************************/
    2000                 : 
    2001           16338 : OGRFeatureDefn * OGRPGLayer::GetLayerDefn()
    2002                 : {
    2003           16338 :     return poFeatureDefn;
    2004                 : }
    2005                 : 
    2006                 : /************************************************************************/
    2007                 : /*                        ReadResultDefinition()                        */
    2008                 : /*                                                                      */
    2009                 : /*      Build a schema from the current resultset.                      */
    2010                 : /************************************************************************/
    2011                 : 
    2012             134 : OGRFeatureDefn *OGRPGLayer::ReadResultDefinition(PGresult *hInitialResultIn)
    2013                 : 
    2014                 : {
    2015             134 :     PGresult            *hResult = hInitialResultIn;
    2016                 : 
    2017                 : /* -------------------------------------------------------------------- */
    2018                 : /*      Parse the returned table information.                           */
    2019                 : /* -------------------------------------------------------------------- */
    2020             134 :     OGRFeatureDefn *poDefn = new OGRFeatureDefn( "sql_statement" );
    2021                 :     int            iRawField;
    2022                 : 
    2023             134 :     poDefn->Reference();
    2024                 : 
    2025             134 :     for( iRawField = 0; iRawField < PQnfields(hResult); iRawField++ )
    2026                 :     {
    2027             452 :         OGRFieldDefn    oField( PQfname(hResult,iRawField), OFTString);
    2028                 :         Oid             nTypeOID;
    2029                 : 
    2030             452 :         nTypeOID = PQftype(hResult,iRawField);
    2031                 : 
    2032             452 :         if( EQUAL(oField.GetNameRef(),"ogc_fid") )
    2033                 :         {
    2034              28 :             if (bHasFid)
    2035                 :             {
    2036                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    2037               0 :                          "More than one ogc_fid column was found in the result of the SQL request. Only last one will be used");
    2038                 :             }
    2039              28 :             bHasFid = TRUE;
    2040              28 :             CPLFree(pszFIDColumn);
    2041              28 :             pszFIDColumn = CPLStrdup(oField.GetNameRef());
    2042              28 :             continue;
    2043                 :         }
    2044             424 :         else if( nTypeOID == poDS->GetGeometryOID()  ||
    2045                 :                  nTypeOID == poDS->GetGeographyOID()  ||
    2046                 :                  EQUAL(oField.GetNameRef(),"ST_AsBinary") ||
    2047                 :                  EQUAL(oField.GetNameRef(),"BinaryBase64") ||
    2048                 :                  EQUAL(oField.GetNameRef(),"ST_AsEWKT") ||
    2049                 :                  EQUAL(oField.GetNameRef(),"ST_AsEWKB") ||
    2050                 :                  EQUAL(oField.GetNameRef(),"EWKBBase64") ||
    2051                 :                  EQUAL(oField.GetNameRef(),"ST_AsText") ||
    2052                 :                  EQUAL(oField.GetNameRef(),"AsBinary") ||
    2053                 :                  EQUAL(oField.GetNameRef(),"asEWKT") ||
    2054                 :                  EQUAL(oField.GetNameRef(),"asEWKB") ||
    2055                 :                  EQUAL(oField.GetNameRef(),"asText") )
    2056                 :         {
    2057              26 :             if (bHasPostGISGeometry || bHasPostGISGeography )
    2058                 :             {
    2059                 :                 CPLError(CE_Warning, CPLE_AppDefined,
    2060               0 :                          "More than one geometry column was found in the result of the SQL request. Only last one will be used");
    2061                 :             }
    2062              26 :             if (nTypeOID == poDS->GetGeographyOID())
    2063               2 :                 bHasPostGISGeography = TRUE;
    2064                 :             else
    2065              24 :                 bHasPostGISGeometry = TRUE;
    2066              26 :             CPLFree(pszGeomColumn);
    2067              26 :             pszGeomColumn = CPLStrdup(oField.GetNameRef());
    2068              26 :             continue;
    2069                 :         }
    2070             398 :         else if( EQUAL(oField.GetNameRef(),"WKB_GEOMETRY") )
    2071                 :         {
    2072              14 :             bHasWkb = TRUE;
    2073              14 :             if( nTypeOID == OIDOID )
    2074               0 :                 bWkbAsOid = TRUE;
    2075              14 :             continue;
    2076                 :         }
    2077                 : 
    2078             384 :         if( nTypeOID == BYTEAOID )
    2079                 :         {
    2080               8 :             oField.SetType( OFTBinary );
    2081                 :         }
    2082             506 :         else if( nTypeOID == CHAROID ||
    2083                 :                  nTypeOID == TEXTOID ||
    2084                 :                  nTypeOID == BPCHAROID ||
    2085                 :                  nTypeOID == VARCHAROID )
    2086                 :         {
    2087             130 :             oField.SetType( OFTString );
    2088                 : 
    2089                 :             /* See http://www.mail-archive.com/pgsql-hackers@postgresql.org/msg57726.html */
    2090                 :             /* nTypmod = width + 4 */
    2091             130 :             int nTypmod = PQfmod(hResult, iRawField);
    2092             130 :             if (nTypmod >= 4 && (nTypeOID == BPCHAROID ||
    2093                 :                                nTypeOID == VARCHAROID ) )
    2094                 :             {
    2095              28 :                 oField.SetWidth( nTypmod - 4);
    2096                 :             }
    2097                 :         }
    2098             246 :         else if( nTypeOID == BOOLOID )
    2099                 :         {
    2100              12 :             oField.SetType( OFTInteger );
    2101              12 :             oField.SetWidth( 1 );
    2102                 :         }
    2103             234 :         else if (nTypeOID == INT2OID )
    2104                 :         {
    2105               8 :             oField.SetType( OFTInteger );
    2106               8 :             oField.SetWidth( 5 );
    2107                 :         }
    2108             226 :         else if (nTypeOID == INT4OID )
    2109                 :         {
    2110              40 :             oField.SetType( OFTInteger );
    2111                 :         }
    2112             186 :         else if ( nTypeOID == INT8OID )
    2113                 :         {
    2114                 :             /* FIXME: OFTInteger can not handle 64bit integers */
    2115              26 :             oField.SetType( OFTInteger );
    2116                 :         }
    2117             200 :         else if( nTypeOID == FLOAT4OID ||
    2118                 :                  nTypeOID == FLOAT8OID )
    2119                 :         {
    2120              40 :             oField.SetType( OFTReal );
    2121                 :         }
    2122             120 :         else if( nTypeOID == NUMERICOID )
    2123                 :         {
    2124                 :             /* See http://www.mail-archive.com/pgsql-hackers@postgresql.org/msg57726.html */
    2125                 :             /* typmod = (width << 16) + precision + 4 */
    2126              16 :             int nTypmod = PQfmod(hResult, iRawField);
    2127              16 :             if (nTypmod >= 4)
    2128                 :             {
    2129              16 :                 int nWidth = (nTypmod - 4) >> 16;
    2130              16 :                 int nPrecision = (nTypmod - 4) & 0xFFFF;
    2131              24 :                 if (nWidth <= 10 && nPrecision == 0)
    2132                 :                 {
    2133               8 :                     oField.SetType( OFTInteger );
    2134               8 :                     oField.SetWidth( nWidth );
    2135                 :                 }
    2136                 :                 else
    2137                 :                 {
    2138               8 :                     oField.SetType( OFTReal );
    2139               8 :                     oField.SetWidth( nWidth );
    2140               8 :                     oField.SetPrecision( nPrecision );
    2141                 :                 }
    2142                 :             }
    2143                 :             else
    2144               0 :                 oField.SetType( OFTReal );
    2145                 :         }
    2146             104 :         else if ( nTypeOID == INT4ARRAYOID )
    2147                 :         {
    2148               8 :             oField.SetType ( OFTIntegerList );
    2149                 :         }
    2150             124 :         else if ( nTypeOID == FLOAT4ARRAYOID ||
    2151                 :                   nTypeOID == FLOAT8ARRAYOID )
    2152                 :         {
    2153              28 :             oField.SetType ( OFTRealList );
    2154                 :         }
    2155              92 :         else if ( nTypeOID == TEXTARRAYOID ||
    2156                 :                   nTypeOID == BPCHARARRAYOID ||
    2157                 :                   nTypeOID == VARCHARARRAYOID )
    2158                 :         {
    2159              24 :             oField.SetType ( OFTStringList );
    2160                 :         }
    2161              44 :         else if ( nTypeOID == DATEOID )
    2162                 :         {
    2163               8 :             oField.SetType( OFTDate );
    2164                 :         }
    2165              36 :         else if ( nTypeOID == TIMEOID )
    2166                 :         {
    2167               8 :             oField.SetType( OFTTime );
    2168                 :         }
    2169              44 :         else if ( nTypeOID == TIMESTAMPOID ||
    2170                 :                   nTypeOID == TIMESTAMPTZOID )
    2171                 :         {
    2172                 :             /* We can't deserialize properly timestamp with time zone */
    2173                 :             /* with binary cursors */
    2174              16 :             if (nTypeOID == TIMESTAMPTZOID)
    2175               8 :                 bCanUseBinaryCursor = FALSE;
    2176                 : 
    2177              16 :             oField.SetType( OFTDateTime );
    2178                 :         }
    2179                 :         else /* unknown type */
    2180                 :         {
    2181              12 :             CPLDebug("PG", "Unhandled OID (%d) for column %d. Defaulting to String.", nTypeOID, iRawField);
    2182              12 :             oField.SetType( OFTString );
    2183                 :         }
    2184                 : 
    2185             384 :         poDefn->AddFieldDefn( &oField );
    2186                 :     }
    2187                 : 
    2188             134 :     return poDefn;
    2189                 : }

Generated by: LCOV version 1.7