LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/pg - ogrpglayer.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 779
Code covered: 75.6 % Executed lines: 589

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpglayer.cpp 19703 2010-05-14 16:46:57Z 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 19703 2010-05-14 16:46:57Z 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            1569 : OGRPGLayer::OGRPGLayer()
      88                 : 
      89                 : {
      90            1569 :     poDS = NULL;
      91                 : 
      92            1569 :     bHasWkb = FALSE;
      93            1569 :     bWkbAsOid = FALSE;
      94            1569 :     bHasPostGISGeometry = FALSE;
      95            1569 :     bHasPostGISGeography = FALSE;
      96            1569 :     pszGeomColumn = NULL;
      97            1569 :     pszQueryStatement = NULL;
      98                 : 
      99            1569 :     bHasFid = FALSE;
     100            1569 :     pszFIDColumn = NULL;
     101                 : 
     102            1569 :     iNextShapeId = 0;
     103            1569 :     nResultOffset = 0;
     104                 : 
     105            1569 :     nCoordDimension = 2; // initialize in case PostGIS is not available
     106                 : 
     107            1569 :     poSRS = NULL;
     108            1569 :     nSRSId = -2; // we haven't even queried the database for it yet.
     109                 : 
     110            1569 :     pszCursorName = CPLStrdup(CPLSPrintf("OGRPGLayerReader%p", this));
     111                 :     
     112            1569 :     hCursorResult = NULL;
     113            1569 :     bCursorActive = FALSE;
     114                 : 
     115            1569 :     bCanUseBinaryCursor = TRUE;
     116                 : 
     117            1569 :     poFeatureDefn = NULL;
     118            1569 :     panMapFieldNameToIndex = NULL;
     119            1569 : }
     120                 : 
     121                 : /************************************************************************/
     122                 : /*                            ~OGRPGLayer()                             */
     123                 : /************************************************************************/
     124                 : 
     125            1569 : OGRPGLayer::~OGRPGLayer()
     126                 : 
     127                 : {
     128            1569 :     if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
     129                 :     {
     130                 :         CPLDebug( "PG", "%d features read on layer '%s'.",
     131                 :                   (int) m_nFeaturesRead,
     132              52 :                   poFeatureDefn->GetName() );
     133                 :     }
     134                 : 
     135            1569 :     ResetReading();
     136                 : 
     137            1569 :     CPLFree( pszGeomColumn );
     138            1569 :     CPLFree( pszFIDColumn );
     139            1569 :     CPLFree( pszQueryStatement );
     140            1569 :     CPLFree( panMapFieldNameToIndex );
     141            1569 :     CPLFree( pszCursorName );
     142                 : 
     143            1569 :     if( poSRS != NULL )
     144               0 :         poSRS->Release();
     145                 : 
     146            1569 :     if( poFeatureDefn )
     147            1566 :         poFeatureDefn->Release();
     148            1569 : }
     149                 : 
     150                 : /************************************************************************/
     151                 : /*                            ResetReading()                            */
     152                 : /************************************************************************/
     153                 : 
     154            3212 : void OGRPGLayer::ResetReading()
     155                 : 
     156                 : {
     157            3212 :     PGconn      *hPGConn = poDS->GetPGConn();
     158            3212 :     CPLString    osCommand;
     159                 : 
     160            3212 :     iNextShapeId = 0;
     161                 : 
     162            3212 :     if( hCursorResult != NULL )
     163                 :     {
     164              93 :         OGRPGClearResult( hCursorResult );
     165                 : 
     166              93 :         if( bCursorActive )
     167                 :         {
     168              93 :             osCommand.Printf("CLOSE %s", pszCursorName );
     169                 : 
     170              93 :             hCursorResult = PQexec(hPGConn, osCommand.c_str());
     171              93 :             OGRPGClearResult( hCursorResult );
     172                 :         }
     173                 : 
     174              93 :         poDS->FlushSoftTransaction();
     175                 : 
     176              93 :         hCursorResult = NULL;
     177            3212 :     }
     178            3212 : }
     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                 : int OGRPGTimeStamp2DMYHMS(GIntBig dt, int *year, int *month, int *day,
     408               0 :                                       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            2273 : OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
     568                 : 
     569                 : {
     570                 : /* -------------------------------------------------------------------- */
     571                 : /*      Create a feature from the current result.                       */
     572                 : /* -------------------------------------------------------------------- */
     573                 :     int         iField;
     574            2273 :     OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
     575                 : 
     576            2273 :     poFeature->SetFID( iNextShapeId );
     577            2273 :     m_nFeaturesRead++;
     578                 : 
     579                 : /* ==================================================================== */
     580                 : /*      Transfer all result fields we can.                              */
     581                 : /* ==================================================================== */
     582           10161 :     for( iField = 0;
     583                 :          iField < PQnfields(hCursorResult);
     584                 :          iField++ )
     585                 :     {
     586                 :         int     iOGRField;
     587                 : 
     588                 : #if !defined(PG_PRE74)
     589            7888 :         int nTypeOID = PQftype(hCursorResult, iField);
     590                 : #endif
     591                 : 
     592                 : /* -------------------------------------------------------------------- */
     593                 : /*      Handle FID.                                                     */
     594                 : /* -------------------------------------------------------------------- */
     595            7888 :         if( bHasFid && EQUAL(PQfname(hCursorResult,iField),pszFIDColumn) )
     596                 :         {
     597                 : #if !defined(PG_PRE74)
     598            2230 :             if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data representation
     599                 :             {
     600               2 :                 if ( nTypeOID == INT4OID)
     601                 :                 {
     602                 :                     int nVal;
     603               2 :                     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            2228 :                 char* pabyData = PQgetvalue(hCursorResult,iRecord,iField);
     618                 :                 /* ogr_pg_20 may crash if PostGIS is unavailable and we don't test pabyData */
     619            2228 :                 if (pabyData)
     620            2228 :                     poFeature->SetFID( atoi(pabyData) );
     621                 :                 else
     622               0 :                     continue;
     623                 :             }
     624                 :         }
     625                 : 
     626                 : /* -------------------------------------------------------------------- */
     627                 : /*      Handle PostGIS geometry                                         */
     628                 : /* -------------------------------------------------------------------- */
     629                 : 
     630           10529 :         if( bHasPostGISGeometry || bHasPostGISGeography )
     631                 :         {
     632            3740 :             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            3740 :             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            3738 :             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            1097 :                 OGRGeometry *poGeometry = NULL;
     705                 : 
     706            1097 :                 pszWKT = PQgetvalue( hCursorResult, iRecord, iField );
     707            1097 :                 pszPostSRID = pszWKT;
     708                 : 
     709                 :                 // optionally strip off PostGIS SRID identifier.  This
     710                 :                 // happens if we got a raw geometry field.
     711            1097 :                 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            1108 :                 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            1086 :                                                     &poGeometry );
     728            1097 :                 if( poGeometry != NULL )
     729                 :                 {
     730              74 :                     poGeometry->assignSpatialReference( poSRS );
     731              74 :                     poFeature->SetGeometryDirectly( poGeometry );
     732                 :                 }
     733                 : 
     734            1097 :                 continue;
     735                 :             }
     736                 :         }
     737                 : /* -------------------------------------------------------------------- */
     738                 : /*      Handle raw binary geometry ... this hasn't been tested in a     */
     739                 : /*      while.                                                          */
     740                 : /* -------------------------------------------------------------------- */
     741            4148 :         else if( EQUAL(PQfname(hCursorResult,iField),"WKB_GEOMETRY") )
     742                 :         {
     743            1141 :             OGRGeometry *poGeometry = NULL;
     744            1141 :             char * pabyData = PQgetvalue( hCursorResult, iRecord, iField);
     745                 : 
     746            1141 :             if( bWkbAsOid )
     747                 :             {
     748                 :                 poGeometry =
     749               0 :                     OIDToGeometry( (Oid) atoi(pabyData) );
     750                 :             }
     751                 :             else
     752                 :             {
     753            1141 :                 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            1141 :                 if (poGeometry == NULL)
     763                 :                 {
     764            1140 :                     poGeometry = BYTEAToGeometry( pabyData );
     765                 :                 }
     766                 :             }
     767                 : 
     768            1141 :             if( poGeometry != NULL )
     769                 :             {
     770             125 :                 poGeometry->assignSpatialReference( poSRS );
     771             125 :                 poFeature->SetGeometryDirectly( poGeometry );
     772                 :             }
     773                 : 
     774            1141 :             continue;
     775                 :         }
     776                 : 
     777                 : /* -------------------------------------------------------------------- */
     778                 : /*      Transfer regular data fields.                                   */
     779                 : /* -------------------------------------------------------------------- */
     780            5648 :         iOGRField = panMapFieldNameToIndex[iField];
     781                 : 
     782            5648 :         if( iOGRField < 0 )
     783            2230 :             continue;
     784                 : 
     785            3418 :         if( PQgetisnull( hCursorResult, iRecord, iField ) )
     786             476 :             continue;
     787                 : 
     788                 :         OGRFieldType eOGRType = 
     789            2942 :             poFeatureDefn->GetFieldDefn(iOGRField)->GetType();
     790                 : 
     791            2942 :         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               4 :                         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            2926 :         else if( eOGRType == OFTRealList )
     854                 :         {
     855                 :             int nCount, i;
     856                 :             double *padfList;
     857                 : 
     858                 : #if !defined(PG_PRE74)
     859              44 :             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               4 :                             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               4 :                             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              40 :                     "{,}", FALSE, FALSE );
     917                 : 
     918              40 :                 nCount = CSLCount(papszTokens);
     919              40 :                 padfList = (double *) CPLCalloc(sizeof(double),nCount);
     920                 : 
     921             120 :                 for( i = 0; i < nCount; i++ )
     922              80 :                     padfList[i] = CPLAtof(papszTokens[i]);
     923              40 :                 CSLDestroy( papszTokens );
     924                 :             }
     925                 : 
     926              44 :             poFeature->SetField( iOGRField, nCount, padfList );
     927              44 :             CPLFree( padfList );
     928                 :         }
     929                 : 
     930            2882 :         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            2940 :         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               2 :                     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               2 :                     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               0 :                     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            2728 :         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            2712 :             if ( PQfformat( hCursorResult, iField ) == 1 &&
    1094                 :                  eOGRType != OFTString ) // Binary data
    1095                 :             {
    1096              18 :                 if ( nTypeOID == BOOLOID )
    1097                 :                 {
    1098                 :                     char cVal;
    1099               2 :                     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               4 :                     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, CPLAtof(str));
    1130               4 :                     CPLFree(str);
    1131                 :                 }
    1132              12 :                 else if ( nTypeOID == INT2OID )
    1133                 :                 {
    1134                 :                     short sVal;
    1135               2 :                     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               2 :                     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               2 :                     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               4 :                     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               2 :                     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            2694 :                 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            2680 :                 else if ( eOGRType == OFTReal )
    1198                 :                 {
    1199                 :                     poFeature->SetField( iOGRField,
    1200             186 :                                 CPLAtof(PQgetvalue( hCursorResult, iRecord, iField )) );
    1201                 :                 }
    1202                 :                 else
    1203                 :                 {
    1204                 :                     poFeature->SetField( iOGRField,
    1205            2494 :                                         PQgetvalue( hCursorResult, iRecord, iField ) );
    1206                 :                 }
    1207                 :             }
    1208                 :         }
    1209                 :     }
    1210                 : 
    1211            2273 :     return poFeature;
    1212                 : }
    1213                 : 
    1214                 : /************************************************************************/
    1215                 : /*                CreateMapFromFieldNameToIndex()                       */
    1216                 : /************************************************************************/
    1217                 : 
    1218                 : /* Evaluating GetFieldIndex() on each field of each feature can be very */
    1219                 : /* expensive if the layer has many fields (total complexity of O(n^2) where */
    1220                 : /* n is the number of fields), so it is valuable to compute the map from */
    1221                 : /* the fetched fields to the OGR field index */
    1222             132 : void OGRPGLayer::CreateMapFromFieldNameToIndex()
    1223                 : {
    1224             132 :     CPLFree(panMapFieldNameToIndex);
    1225             132 :     panMapFieldNameToIndex = NULL;
    1226             132 :     if ( PQresultStatus(hCursorResult)  == PGRES_TUPLES_OK )
    1227                 :     {
    1228                 :         panMapFieldNameToIndex =
    1229             132 :                 (int*)CPLMalloc(sizeof(int) * PQnfields(hCursorResult));
    1230            1131 :         for( int iField = 0;
    1231                 :             iField < PQnfields(hCursorResult);
    1232                 :             iField++ )
    1233                 :         {
    1234                 :             panMapFieldNameToIndex[iField] =
    1235             999 :                     poFeatureDefn->GetFieldIndex(PQfname(hCursorResult,iField));
    1236                 :         }
    1237                 :     }
    1238             132 : }
    1239                 : 
    1240                 : 
    1241                 : /************************************************************************/
    1242                 : /*                     SetInitialQueryCursor()                          */
    1243                 : /************************************************************************/
    1244                 : 
    1245             119 : void OGRPGLayer::SetInitialQueryCursor()
    1246                 : {
    1247             119 :     PGconn      *hPGConn = poDS->GetPGConn();
    1248             119 :     CPLString   osCommand;
    1249                 : 
    1250             119 :     CPLAssert( pszQueryStatement != NULL );
    1251                 : 
    1252             119 :     poDS->FlushSoftTransaction();
    1253             119 :     poDS->SoftStartTransaction();
    1254                 : 
    1255             121 :     if ( poDS->bUseBinaryCursor && bCanUseBinaryCursor )
    1256                 :         osCommand.Printf( "DECLARE %s BINARY CURSOR for %s",
    1257               2 :                             pszCursorName, pszQueryStatement );
    1258                 :     else
    1259                 :         osCommand.Printf( "DECLARE %s CURSOR for %s",
    1260             117 :                             pszCursorName, pszQueryStatement );
    1261                 : 
    1262             119 :     hCursorResult = PQexec(hPGConn, osCommand );
    1263             119 :     OGRPGClearResult( hCursorResult );
    1264                 : 
    1265             119 :     osCommand.Printf( "FETCH %d in %s", CURSOR_PAGE, pszCursorName );
    1266             119 :     hCursorResult = PQexec(hPGConn, osCommand );
    1267                 : 
    1268             119 :     bCursorActive = TRUE;
    1269                 : 
    1270             119 :     CreateMapFromFieldNameToIndex();
    1271                 : 
    1272             119 :     nResultOffset = 0;
    1273             119 : }
    1274                 : 
    1275                 : /************************************************************************/
    1276                 : /*                         GetNextRawFeature()                          */
    1277                 : /************************************************************************/
    1278                 : 
    1279            2286 : OGRFeature *OGRPGLayer::GetNextRawFeature()
    1280                 : 
    1281                 : {
    1282            2286 :     PGconn      *hPGConn = poDS->GetPGConn();
    1283            2286 :     CPLString   osCommand;
    1284                 : 
    1285                 : /* -------------------------------------------------------------------- */
    1286                 : /*      Do we need to establish an initial query?                       */
    1287                 : /* -------------------------------------------------------------------- */
    1288            2286 :     if( iNextShapeId == 0 && hCursorResult == NULL )
    1289                 :     {
    1290              85 :         SetInitialQueryCursor();
    1291                 :     }
    1292                 : 
    1293                 : /* -------------------------------------------------------------------- */
    1294                 : /*      Are we in some sort of error condition?                         */
    1295                 : /* -------------------------------------------------------------------- */
    1296            2286 :     if( hCursorResult == NULL
    1297                 :         || PQresultStatus(hCursorResult) != PGRES_TUPLES_OK )
    1298                 :     {
    1299               0 :         CPLDebug( "PG", "PQclear() on an error condition");
    1300                 : 
    1301               0 :         OGRPGClearResult( hCursorResult );
    1302                 : 
    1303               0 :         iNextShapeId = MAX(1,iNextShapeId);
    1304               0 :         return NULL;
    1305                 :     }
    1306                 : 
    1307                 : /* -------------------------------------------------------------------- */
    1308                 : /*      Do we need to fetch more records?                               */
    1309                 : /* -------------------------------------------------------------------- */
    1310            2286 :     if( PQntuples(hCursorResult) > 0 &&
    1311                 :         nResultOffset >= PQntuples(hCursorResult)
    1312                 :         && bCursorActive )
    1313                 :     {
    1314              27 :         OGRPGClearResult( hCursorResult );
    1315                 :         
    1316              27 :         osCommand.Printf( "FETCH %d in %s", CURSOR_PAGE, pszCursorName );
    1317              27 :         hCursorResult = PQexec(hPGConn, osCommand );
    1318                 : 
    1319              27 :         nResultOffset = 0;
    1320                 :     }
    1321                 : 
    1322                 : /* -------------------------------------------------------------------- */
    1323                 : /*      Are we out of results?  If so complete the transaction, and     */
    1324                 : /*      cleanup, but don't reset the next shapeid.                      */
    1325                 : /* -------------------------------------------------------------------- */
    1326            2286 :     if( nResultOffset >= PQntuples(hCursorResult) )
    1327                 :     {
    1328              26 :         OGRPGClearResult( hCursorResult );
    1329                 : 
    1330              26 :         if( bCursorActive )
    1331                 :         {
    1332              26 :             osCommand.Printf( "CLOSE %s", pszCursorName );
    1333                 : 
    1334              26 :             hCursorResult = PQexec(hPGConn, osCommand);
    1335              26 :             OGRPGClearResult( hCursorResult );
    1336                 :         }
    1337                 : 
    1338              26 :         poDS->FlushSoftTransaction();
    1339                 : 
    1340              26 :         hCursorResult = NULL;
    1341              26 :         bCursorActive = FALSE;
    1342                 : 
    1343              26 :         iNextShapeId = MAX(1,iNextShapeId);
    1344                 : 
    1345              26 :         return NULL;
    1346                 :     }
    1347                 : 
    1348                 : 
    1349                 : /* -------------------------------------------------------------------- */
    1350                 : /*      Create a feature from the current result.                       */
    1351                 : /* -------------------------------------------------------------------- */
    1352            2260 :     OGRFeature *poFeature = RecordToFeature( nResultOffset );
    1353                 : 
    1354            2260 :     nResultOffset++;
    1355            2260 :     iNextShapeId++;
    1356                 : 
    1357            2260 :     return poFeature;
    1358                 : }
    1359                 : 
    1360                 : /************************************************************************/
    1361                 : /*                           SetNextByIndex()                           */
    1362                 : /************************************************************************/
    1363                 : 
    1364               4 : OGRErr OGRPGLayer::SetNextByIndex( long nIndex )
    1365                 : 
    1366                 : {
    1367               4 :     if( !TestCapability(OLCFastSetNextByIndex) )
    1368               0 :         return OGRLayer::SetNextByIndex(nIndex);
    1369                 : 
    1370               4 :     if( nIndex == iNextShapeId)
    1371                 :     {
    1372               0 :         return OGRERR_NONE;
    1373                 :     }
    1374                 :     
    1375               4 :     if( nIndex < 0 )
    1376                 :     {
    1377               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid index");
    1378               0 :         return OGRERR_FAILURE;
    1379                 :     }
    1380                 :     
    1381               4 :     if( nIndex == 0 )
    1382                 :     {
    1383               0 :         ResetReading();
    1384               0 :         return OGRERR_NONE;
    1385                 :     }
    1386                 :     
    1387               4 :     PGconn      *hPGConn = poDS->GetPGConn();
    1388               4 :     CPLString   osCommand;
    1389                 :     
    1390               4 :     if (hCursorResult == NULL )
    1391                 :     {
    1392               2 :         SetInitialQueryCursor();
    1393                 :     }
    1394                 :     
    1395               4 :     OGRPGClearResult( hCursorResult );
    1396                 :     
    1397               4 :     osCommand.Printf( "FETCH ABSOLUTE %ld in %s", nIndex+1, pszCursorName );
    1398               4 :     hCursorResult = PQexec(hPGConn, osCommand );
    1399                 :     
    1400               4 :     if (PQresultStatus(hCursorResult) != PGRES_TUPLES_OK ||
    1401                 :         PQntuples(hCursorResult) != 1)
    1402                 :     {
    1403                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1404               0 :                   "Attempt to read feature at invalid index (%ld).", nIndex );
    1405                 :                   
    1406               0 :         OGRPGClearResult( hCursorResult );
    1407                 : 
    1408               0 :         if( bCursorActive )
    1409                 :         {
    1410               0 :             osCommand.Printf( "CLOSE %s", pszCursorName );
    1411                 : 
    1412               0 :             hCursorResult = PQexec(hPGConn, osCommand);
    1413               0 :             OGRPGClearResult( hCursorResult );
    1414                 :         }
    1415                 : 
    1416               0 :         poDS->FlushSoftTransaction();
    1417                 : 
    1418               0 :         hCursorResult = NULL;
    1419               0 :         bCursorActive = FALSE;
    1420                 : 
    1421               0 :         iNextShapeId = 0;
    1422                 : 
    1423               4 :         return OGRERR_FAILURE;
    1424                 :     }
    1425                 : 
    1426               4 :     nResultOffset = 0;
    1427               4 :     iNextShapeId = nIndex;
    1428                 :     
    1429               4 :     return OGRERR_NONE;
    1430                 : }
    1431                 : 
    1432                 : /************************************************************************/
    1433                 : /*                           HEXToGeometry()                            */
    1434                 : /************************************************************************/
    1435                 : 
    1436              12 : OGRGeometry *OGRPGLayer::HEXToGeometry( const char *pszBytea )
    1437                 : 
    1438                 : {
    1439                 :     GByte   *pabyWKB;
    1440              12 :     int     nWKBLength=0;
    1441                 :     OGRGeometry *poGeometry;
    1442                 : 
    1443              12 :     if( pszBytea == NULL )
    1444               0 :         return NULL;
    1445                 : 
    1446              12 :     pabyWKB = CPLHexToBinary(pszBytea, &nWKBLength);
    1447                 : 
    1448              12 :     poGeometry = EWKBToGeometry(pabyWKB, nWKBLength);
    1449                 : 
    1450              12 :     CPLFree(pabyWKB);
    1451                 : 
    1452              12 :     return poGeometry;
    1453                 : }
    1454                 : 
    1455                 : 
    1456                 : /************************************************************************/
    1457                 : /*                          EWKBToGeometry()                            */
    1458                 : /************************************************************************/
    1459                 : 
    1460              14 : OGRGeometry *OGRPGLayer::EWKBToGeometry( GByte *pabyWKB, int nLength )
    1461                 : 
    1462                 : {
    1463              14 :     OGRGeometry *poGeometry = NULL;
    1464              14 :     unsigned int ewkbFlags = 0;
    1465                 :     
    1466              14 :     if (nLength < 5)
    1467                 :     {
    1468                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1469               0 :                   "Invalid EWKB content : %d bytes", nLength );
    1470               0 :         return NULL;
    1471                 :     }
    1472                 : 
    1473                 : /* -------------------------------------------------------------------- */
    1474                 : /*      Detect XYZM variant of PostGIS EWKB                             */
    1475                 : /*                                                                      */
    1476                 : /*      OGR does not support parsing M coordinate,                      */
    1477                 : /*      so we return NULL geometry.                                     */
    1478                 : /* -------------------------------------------------------------------- */
    1479              14 :     memcpy(&ewkbFlags, pabyWKB+1, 4);
    1480              14 :     OGRwkbByteOrder eByteOrder = (pabyWKB[0] == 0 ? wkbXDR : wkbNDR);
    1481              14 :     if( OGR_SWAP( eByteOrder ) )
    1482               0 :         ewkbFlags= CPL_SWAP32(ewkbFlags);
    1483                 : 
    1484              14 :     if (ewkbFlags & 0x40000000)
    1485                 :     {
    1486                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1487               7 :             "Reading EWKB with 4-dimensional coordinates (XYZM) is not supported" );
    1488                 : 
    1489               7 :         return NULL;
    1490                 :     }
    1491                 : 
    1492                 : /* -------------------------------------------------------------------- */
    1493                 : /*      PostGIS EWKB format includes an  SRID, but this won't be        */
    1494                 : /*      understood by OGR, so if the SRID flag is set, we remove the    */
    1495                 : /*      SRID (bytes at offset 5 to 8).                                  */
    1496                 : /* -------------------------------------------------------------------- */
    1497               7 :     if( nLength > 9 &&
    1498                 :         ((pabyWKB[0] == 0 /* big endian */ && (pabyWKB[1] & 0x20) )
    1499                 :         || (pabyWKB[0] != 0 /* little endian */ && (pabyWKB[4] & 0x20))) )
    1500                 :     {
    1501               0 :         memmove( pabyWKB+5, pabyWKB+9, nLength-9 );
    1502               0 :         nLength -= 4;
    1503               0 :         if( pabyWKB[0] == 0 )
    1504               0 :             pabyWKB[1] &= (~0x20);
    1505                 :         else
    1506               0 :             pabyWKB[4] &= (~0x20);
    1507                 :     }
    1508                 : 
    1509                 : /* -------------------------------------------------------------------- */
    1510                 : /*      Try to ingest the geometry.                                     */
    1511                 : /* -------------------------------------------------------------------- */
    1512               7 :     OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nLength );
    1513                 : 
    1514               7 :     return poGeometry;
    1515                 : }
    1516                 : 
    1517                 : /************************************************************************/
    1518                 : /*                           GeometryToHex()                            */
    1519                 : /************************************************************************/
    1520              11 : char *OGRPGLayer::GeometryToHex( OGRGeometry * poGeometry, int nSRSId )
    1521                 : {
    1522                 :     GByte       *pabyWKB;
    1523                 :     char        *pszTextBuf;
    1524                 :     char        *pszTextBufCurrent;
    1525                 :     char        *pszHex;
    1526                 : 
    1527              11 :     int nWkbSize = poGeometry->WkbSize();
    1528              11 :     pabyWKB = (GByte *) CPLMalloc(nWkbSize);
    1529                 : 
    1530              11 :     if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
    1531                 :     {
    1532               0 :         CPLFree( pabyWKB );
    1533               0 :         return CPLStrdup("");
    1534                 :     }
    1535                 : 
    1536                 :     /* When converting to hex, each byte takes 2 hex characters.  In addition
    1537                 :        we add in 8 characters to represent the SRID integer in hex, and
    1538                 :        one for a null terminator */
    1539                 : 
    1540              11 :     int pszSize = nWkbSize*2 + 8 + 1;
    1541              11 :     pszTextBuf = (char *) CPLMalloc(pszSize);
    1542              11 :     pszTextBufCurrent = pszTextBuf;
    1543                 : 
    1544                 :     /* Convert the 1st byte, which is the endianess flag, to hex. */
    1545              11 :     pszHex = CPLBinaryToHex( 1, pabyWKB );
    1546              11 :     strcpy(pszTextBufCurrent, pszHex );
    1547              11 :     CPLFree ( pszHex );
    1548              11 :     pszTextBufCurrent += 2;
    1549                 : 
    1550                 :     /* Next, get the geom type which is bytes 2 through 5 */
    1551                 :     GUInt32 geomType;
    1552              11 :     memcpy( &geomType, pabyWKB+1, 4 );
    1553                 : 
    1554                 :     /* Now add the SRID flag if an SRID is provided */
    1555              11 :     if (nSRSId != -1)
    1556                 :     {
    1557                 :         /* Change the flag to wkbNDR (little) endianess */
    1558               0 :         GUInt32 nGSrsFlag = CPL_LSBWORD32( WKBSRIDFLAG );
    1559                 :         /* Apply the flag */
    1560               0 :         geomType = geomType | nGSrsFlag;
    1561                 :     }
    1562                 : 
    1563                 :     /* Now write the geom type which is 4 bytes */
    1564              11 :     pszHex = CPLBinaryToHex( 4, (GByte*) &geomType );
    1565              11 :     strcpy(pszTextBufCurrent, pszHex );
    1566              11 :     CPLFree ( pszHex );
    1567              11 :     pszTextBufCurrent += 8;
    1568                 : 
    1569                 :     /* Now include SRID if provided */
    1570              11 :     if (nSRSId != -1)
    1571                 :     {
    1572                 :         /* Force the srsid to wkbNDR (little) endianess */
    1573               0 :         GUInt32 nGSRSId = CPL_LSBWORD32( nSRSId );
    1574               0 :         pszHex = CPLBinaryToHex( sizeof(nGSRSId),(GByte*) &nGSRSId );
    1575               0 :         strcpy(pszTextBufCurrent, pszHex );
    1576               0 :         CPLFree ( pszHex );
    1577               0 :         pszTextBufCurrent += 8;
    1578                 :     }
    1579                 : 
    1580                 :     /* Copy the rest of the data over - subtract
    1581                 :        5 since we already copied 5 bytes above */
    1582              11 :     pszHex = CPLBinaryToHex( nWkbSize - 5, pabyWKB + 5 );
    1583              11 :     strcpy(pszTextBufCurrent, pszHex );
    1584              11 :     CPLFree ( pszHex );
    1585                 : 
    1586              11 :     CPLFree( pabyWKB );
    1587                 : 
    1588              11 :     return pszTextBuf;
    1589                 : }
    1590                 : 
    1591                 : 
    1592                 : /************************************************************************/
    1593                 : /*                        BYTEAToGByteArray()                           */
    1594                 : /************************************************************************/
    1595                 : 
    1596            1154 : GByte* OGRPGLayer::BYTEAToGByteArray( const char *pszBytea, int* pnLength )
    1597                 : {
    1598                 :     GByte* pabyData;
    1599            1154 :     int iSrc=0, iDst=0;
    1600                 : 
    1601            1154 :     if( pszBytea == NULL )
    1602                 :     {
    1603               0 :         if (pnLength) *pnLength = 0;
    1604               0 :         return NULL;
    1605                 :     }
    1606                 : 
    1607            1154 :     pabyData = (GByte *) CPLMalloc(strlen(pszBytea));
    1608                 : 
    1609           39982 :     while( pszBytea[iSrc] != '\0' )
    1610                 :     {
    1611           37674 :         if( pszBytea[iSrc] == '\\' )
    1612                 :         {
    1613           47347 :             if( pszBytea[iSrc+1] >= '0' && pszBytea[iSrc+1] <= '9' )
    1614                 :             {
    1615           23652 :                 if (pszBytea[iSrc+2] == '\0' ||
    1616                 :                     pszBytea[iSrc+3] == '\0')
    1617               0 :                     break;
    1618                 : 
    1619                 :                 pabyData[iDst++] =
    1620                 :                     (pszBytea[iSrc+1] - 48) * 64
    1621                 :                     + (pszBytea[iSrc+2] - 48) * 8
    1622           23652 :                     + (pszBytea[iSrc+3] - 48) * 1;
    1623           23652 :                 iSrc += 4;
    1624                 :             }
    1625                 :             else
    1626                 :             {
    1627              43 :                 if (pszBytea[iSrc+1] == '\0')
    1628               0 :                     break;
    1629                 : 
    1630              43 :                 pabyData[iDst++] = pszBytea[iSrc+1];
    1631              43 :                 iSrc += 2;
    1632                 :             }
    1633                 :         }
    1634                 :         else
    1635                 :         {
    1636           13979 :             pabyData[iDst++] = pszBytea[iSrc++];
    1637                 :         }
    1638                 :     }
    1639            1154 :     if (pnLength) *pnLength = iDst;
    1640                 : 
    1641            1154 :     return pabyData;
    1642                 : }
    1643                 : 
    1644                 : 
    1645                 : /************************************************************************/
    1646                 : /*                          BYTEAToGeometry()                           */
    1647                 : /************************************************************************/
    1648                 : 
    1649            1140 : OGRGeometry *OGRPGLayer::BYTEAToGeometry( const char *pszBytea )
    1650                 : 
    1651                 : {
    1652                 :     GByte       *pabyWKB;
    1653            1140 :     int nLen=0;
    1654                 :     OGRGeometry *poGeometry;
    1655                 : 
    1656            1140 :     if( pszBytea == NULL )
    1657               0 :         return NULL;
    1658                 : 
    1659            1140 :     pabyWKB = BYTEAToGByteArray(pszBytea, &nLen);
    1660                 : 
    1661            1140 :     poGeometry = NULL;
    1662            1140 :     OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nLen );
    1663                 : 
    1664            1140 :     CPLFree( pabyWKB );
    1665            1140 :     return poGeometry;
    1666                 : }
    1667                 : 
    1668                 : 
    1669                 : /************************************************************************/
    1670                 : /*                        GByteArrayToBYTEA()                           */
    1671                 : /************************************************************************/
    1672                 : 
    1673              38 : char* OGRPGLayer::GByteArrayToBYTEA( const GByte* pabyData, int nLen)
    1674                 : {
    1675                 :     char* pszTextBuf;
    1676                 : 
    1677              38 :     pszTextBuf = (char *) CPLMalloc(nLen*5+1);
    1678                 : 
    1679              38 :     int  iSrc, iDst=0;
    1680                 : 
    1681           10253 :     for( iSrc = 0; iSrc < nLen; iSrc++ )
    1682                 :     {
    1683           16781 :         if( pabyData[iSrc] < 40 || pabyData[iSrc] > 126
    1684                 :             || pabyData[iSrc] == '\\' )
    1685                 :         {
    1686            6566 :             sprintf( pszTextBuf+iDst, "\\\\%03o", pabyData[iSrc] );
    1687            6566 :             iDst += 5;
    1688                 :         }
    1689                 :         else
    1690            3649 :             pszTextBuf[iDst++] = pabyData[iSrc];
    1691                 :     }
    1692              38 :     pszTextBuf[iDst] = '\0';
    1693                 : 
    1694              38 :     return pszTextBuf;
    1695                 : }
    1696                 : 
    1697                 : /************************************************************************/
    1698                 : /*                          GeometryToBYTEA()                           */
    1699                 : /************************************************************************/
    1700                 : 
    1701              34 : char *OGRPGLayer::GeometryToBYTEA( OGRGeometry * poGeometry )
    1702                 : 
    1703                 : {
    1704              34 :     int         nWkbSize = poGeometry->WkbSize();
    1705                 :     GByte       *pabyWKB;
    1706                 :     char        *pszTextBuf;
    1707                 : 
    1708              34 :     pabyWKB = (GByte *) CPLMalloc(nWkbSize);
    1709              34 :     if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
    1710                 :     {
    1711               0 :         CPLFree(pabyWKB);
    1712               0 :         return CPLStrdup("");
    1713                 :     }
    1714                 : 
    1715              34 :     pszTextBuf = GByteArrayToBYTEA( pabyWKB, nWkbSize );
    1716              34 :     CPLFree(pabyWKB);
    1717                 : 
    1718              34 :     return pszTextBuf;
    1719                 : }
    1720                 : 
    1721                 : /************************************************************************/
    1722                 : /*                          OIDToGeometry()                             */
    1723                 : /************************************************************************/
    1724                 : 
    1725               0 : OGRGeometry *OGRPGLayer::OIDToGeometry( Oid oid )
    1726                 : 
    1727                 : {
    1728               0 :     PGconn      *hPGConn = poDS->GetPGConn();
    1729                 :     GByte       *pabyWKB;
    1730                 :     int         fd, nBytes;
    1731                 :     OGRGeometry *poGeometry;
    1732                 : 
    1733                 : #define MAX_WKB 500000
    1734                 : 
    1735               0 :     if( oid == 0 )
    1736               0 :         return NULL;
    1737                 : 
    1738               0 :     fd = lo_open( hPGConn, oid, INV_READ );
    1739               0 :     if( fd < 0 )
    1740               0 :         return NULL;
    1741                 : 
    1742               0 :     pabyWKB = (GByte *) CPLMalloc(MAX_WKB);
    1743               0 :     nBytes = lo_read( hPGConn, fd, (char *) pabyWKB, MAX_WKB );
    1744               0 :     lo_close( hPGConn, fd );
    1745                 : 
    1746               0 :     poGeometry = NULL;
    1747               0 :     OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nBytes );
    1748                 : 
    1749               0 :     CPLFree( pabyWKB );
    1750                 : 
    1751               0 :     return poGeometry;
    1752                 : }
    1753                 : 
    1754                 : /************************************************************************/
    1755                 : /*                           GeometryToOID()                            */
    1756                 : /************************************************************************/
    1757                 : 
    1758               0 : Oid OGRPGLayer::GeometryToOID( OGRGeometry * poGeometry )
    1759                 : 
    1760                 : {
    1761               0 :     PGconn      *hPGConn = poDS->GetPGConn();
    1762               0 :     int         nWkbSize = poGeometry->WkbSize();
    1763                 :     GByte       *pabyWKB;
    1764                 :     Oid         oid;
    1765                 :     int         fd, nBytesWritten;
    1766                 : 
    1767               0 :     pabyWKB = (GByte *) CPLMalloc(nWkbSize);
    1768               0 :     if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
    1769               0 :         return 0;
    1770                 : 
    1771               0 :     oid = lo_creat( hPGConn, INV_READ|INV_WRITE );
    1772                 : 
    1773               0 :     fd = lo_open( hPGConn, oid, INV_WRITE );
    1774               0 :     nBytesWritten = lo_write( hPGConn, fd, (char *) pabyWKB, nWkbSize );
    1775               0 :     lo_close( hPGConn, fd );
    1776                 : 
    1777               0 :     if( nBytesWritten != nWkbSize )
    1778                 :     {
    1779                 :         CPLDebug( "PG",
    1780                 :                   "Only wrote %d bytes of %d intended for (fd=%d,oid=%d).\n",
    1781               0 :                   nBytesWritten, nWkbSize, fd, oid );
    1782                 :     }
    1783                 : 
    1784               0 :     CPLFree( pabyWKB );
    1785                 : 
    1786               0 :     return oid;
    1787                 : }
    1788                 : 
    1789                 : /************************************************************************/
    1790                 : /*                          StartTransaction()                          */
    1791                 : /************************************************************************/
    1792                 : 
    1793              15 : OGRErr OGRPGLayer::StartTransaction()
    1794                 : 
    1795                 : {
    1796              15 :     return poDS->SoftStartTransaction();
    1797                 : }
    1798                 : 
    1799                 : /************************************************************************/
    1800                 : /*                         CommitTransaction()                          */
    1801                 : /************************************************************************/
    1802                 : 
    1803              15 : OGRErr OGRPGLayer::CommitTransaction()
    1804                 : 
    1805                 : {
    1806              15 :     return poDS->SoftCommit();
    1807                 : }
    1808                 : 
    1809                 : /************************************************************************/
    1810                 : /*                        RollbackTransaction()                         */
    1811                 : /************************************************************************/
    1812                 : 
    1813               0 : OGRErr OGRPGLayer::RollbackTransaction()
    1814                 : 
    1815                 : {
    1816               0 :     return poDS->SoftRollback();
    1817                 : }
    1818                 : 
    1819                 : /************************************************************************/
    1820                 : /*                           GetSpatialRef()                            */
    1821                 : /************************************************************************/
    1822                 : 
    1823             218 : OGRSpatialReference *OGRPGLayer::GetSpatialRef()
    1824                 : 
    1825                 : {
    1826             218 :     if( poSRS == NULL && nSRSId > -1 )
    1827                 :     {
    1828               0 :         poSRS = poDS->FetchSRS( nSRSId );
    1829               0 :         if( poSRS != NULL )
    1830               0 :             poSRS->Reference();
    1831                 :         else
    1832               0 :             nSRSId = -1;
    1833                 :     }
    1834                 : 
    1835             218 :     return poSRS;
    1836                 : }
    1837                 : 
    1838                 : /************************************************************************/
    1839                 : /*                            GetFIDColumn()                            */
    1840                 : /************************************************************************/
    1841                 : 
    1842               4 : const char *OGRPGLayer::GetFIDColumn() 
    1843                 : 
    1844                 : {
    1845               4 :     if( pszFIDColumn != NULL )
    1846               2 :         return pszFIDColumn;
    1847                 :     else
    1848               2 :         return "";
    1849                 : }
    1850                 : 
    1851                 : /************************************************************************/
    1852                 : /*                         GetGeometryColumn()                          */
    1853                 : /************************************************************************/
    1854                 : 
    1855               6 : const char *OGRPGLayer::GetGeometryColumn() 
    1856                 : 
    1857                 : {
    1858               6 :     if( pszGeomColumn != NULL )
    1859               6 :         return pszGeomColumn;
    1860                 :     else
    1861               0 :         return "";
    1862                 : }
    1863                 : 
    1864                 : /************************************************************************/
    1865                 : /*                             GetExtent()                              */
    1866                 : /************************************************************************/
    1867                 : 
    1868                 : OGRErr OGRPGLayer::RunGetExtentRequest( OGREnvelope *psExtent, int bForce,
    1869               4 :                                         CPLString osCommand)
    1870                 : {
    1871               4 :     if ( psExtent == NULL )
    1872               0 :         return OGRERR_FAILURE;
    1873                 : 
    1874               4 :     if ( TestCapability(OLCFastGetExtent) || bHasPostGISGeography )
    1875                 :     {
    1876               2 :         PGconn      *hPGConn = poDS->GetPGConn();
    1877               2 :         PGresult    *hResult = NULL;
    1878                 : 
    1879               2 :         hResult = PQexec( hPGConn, osCommand );
    1880               2 :         if( ! hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK || PQgetisnull(hResult,0,0) )
    1881                 :         {
    1882               0 :             OGRPGClearResult( hResult );
    1883               0 :             CPLDebug("PG","Unable to get extent by PostGIS. Using standard OGRLayer method.");
    1884               0 :             return OGRPGLayer::GetExtent( psExtent, bForce );
    1885                 :         }
    1886                 : 
    1887               2 :         char * pszBox = PQgetvalue(hResult,0,0);
    1888                 :         char * ptr, *ptrEndParenthesis;
    1889                 :         char szVals[64*6+6];
    1890                 : 
    1891               2 :         ptr = strchr(pszBox, '(');
    1892               2 :         if (ptr)
    1893               2 :             ptr ++;
    1894               2 :         if (ptr == NULL ||
    1895                 :             (ptrEndParenthesis = strchr(ptr, ')')) == NULL ||
    1896                 :             ptrEndParenthesis - ptr > (int)(sizeof(szVals) - 1))
    1897                 :         {
    1898                 :             CPLError( CE_Failure, CPLE_IllegalArg,
    1899               0 :                       "Bad extent representation: '%s'", pszBox);
    1900                 : 
    1901               0 :             OGRPGClearResult( hResult );
    1902               0 :             return OGRERR_FAILURE;
    1903                 :         }
    1904                 : 
    1905               2 :         strncpy(szVals,ptr,ptrEndParenthesis - ptr);
    1906               2 :         szVals[ptrEndParenthesis - ptr] = '\0';
    1907                 : 
    1908               2 :         char ** papszTokens = CSLTokenizeString2(szVals," ,",CSLT_HONOURSTRINGS);
    1909               2 :         int nTokenCnt = poDS->sPostGISVersion.nMajor >= 1 ? 4 : 6;
    1910                 : 
    1911               2 :         if ( CSLCount(papszTokens) != nTokenCnt )
    1912                 :         {
    1913                 :             CPLError( CE_Failure, CPLE_IllegalArg,
    1914               0 :                       "Bad extent representation: '%s'", pszBox);
    1915               0 :             CSLDestroy(papszTokens);
    1916                 : 
    1917               0 :             OGRPGClearResult( hResult );
    1918               0 :             return OGRERR_FAILURE;
    1919                 :         }
    1920                 : 
    1921                 :         // Take X,Y coords
    1922                 :         // For PostGis ver >= 1.0.0 -> Tokens: X1 Y1 X2 Y2 (nTokenCnt = 4)
    1923                 :         // For PostGIS ver < 1.0.0 -> Tokens: X1 Y1 Z1 X2 Y2 Z2 (nTokenCnt = 6)
    1924                 :         // =>   X2 index calculated as nTokenCnt/2
    1925                 :         //      Y2 index caluclated as nTokenCnt/2+1
    1926                 :         
    1927               2 :         psExtent->MinX = CPLAtof( papszTokens[0] );
    1928               2 :         psExtent->MinY = CPLAtof( papszTokens[1] );
    1929               2 :         psExtent->MaxX = CPLAtof( papszTokens[nTokenCnt/2] );
    1930               2 :         psExtent->MaxY = CPLAtof( papszTokens[nTokenCnt/2+1] );
    1931                 : 
    1932               2 :         CSLDestroy(papszTokens);
    1933               2 :         OGRPGClearResult( hResult );
    1934                 : 
    1935               2 :         return OGRERR_NONE;
    1936                 :     }
    1937                 : 
    1938               2 :     return OGRLayer::GetExtent( psExtent, bForce );
    1939                 : }

Generated by: LTP GCOV extension version 1.5