LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpglayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 783 587 75.0 %
Date: 2010-01-09 Functions: 32 25 78.1 %

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

Generated by: LCOV version 1.7