LTP GCOV extension - code coverage report
Current view: directory - frmts/wktraster - wktrasterdataset.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 532
Code covered: 13.5 % Executed lines: 72

       1                 : /*************************************************************************
       2                 :  * File :    wktrasterdataset.cpp
       3                 :  * Project:  WKT Raster driver
       4                 :  * Purpose:  GDAL Dataset code for WKTRaster driver 
       5                 :  * Author:   Jorge Arevalo, jorgearevalo@gis4free.org
       6                 :  * 
       7                 :  * Last changes:
       8                 :  * $Id: wktrasterdataset.cpp 19624 2010-05-07 10:33:25Z jorgearevalo $
       9                 :  *
      10                 :  * This class represents a dataset of the PostGIS Raster type, formally
      11                 :  * known as "WKT Raster" type. This type implements a complete raster
      12                 :  * structure for the PostGIS extension. A single attribute of type 
      13                 :  * "raster" can store:
      14                 :  *  - a complete image
      15                 :  *  - an image tile
      16                 :  *  - a "raster object". A object result from the rasterization of a
      17                 :  *    vector structure
      18                 :  * Hence, a table with a column of type "raster", can store:
      19                 :  *  a) an image warehouse of untiled and (possibly) unrelated images. These
      20                 :  *     images may or may not overlap since every image has its own 
      21                 :  *     georeference. They may  also have no georeference at all.
      22                 :  *  b) an irregularly tiled raster coverage. It might not necessarily be
      23                 :  *     rectangular, there might be some missing tiles, and they might be 
      24                 :  *     different sizes. Tiles should not overlap.
      25                 :  *  c) a regularly tiled raster coverage. It might not necessarily be 
      26                 :  *     rectangular, there might be some missing tiles, and the tiles should
      27                 :  *     be the same size. Tiles should not overlap.
      28                 :  *  d) a rectangular regularly tiled raster coverage. It is necessarily
      29                 :  *     rectangular, there are no missing tiles, they are all the same size
      30                 :  *     and they do not overlap.
      31                 :  *  e) a tiled image. It is necessarily rectangular, there are no missing
      32                 :  *     tiles they are all the same size, and they do not overlap. This 
      33                 :  *     type is different from type d) in that it does not represent a 
      34                 :  *     complete coverage; other images forming the rest of the coverage 
      35                 :  *     are stored as other tables of tiled images. This structure is not 
      36                 :  *     very practical from a GIS analytical point of view since any 
      37                 :  *     operations applied to the coverage must also be applied to every
      38                 :  *     table.
      39                 :  *  f) a raster object coverage resulting from the rasterization of a 
      40                 :  *     vector coverage. Each vector feature becomes a small raster with
      41                 :  *     the same extent as the original vector feature. This type of 
      42                 :  *     coverage is not necessarily complete, nor rectangular; tiles should
      43                 :  *     be of different sizes and might overlap. It all depends on the 
      44                 :  *     characteristics of the vector layer being rasterized. An exhaustive
      45                 :  *     (or continuous) layer of mutually exclusive geometries (without 
      46                 :  *     gaps or holes like a forest cover) would result in a raster object
      47                 :  *     coverage in which significant pixels (withdata values) would not
      48                 :  *     overlap, but non-significant pixels (nodata values) would. On the 
      49                 :  *     other end of the spectrum, a discontinuous layer of mutually 
      50                 :  *     exclusive geometries (like a lake or building layer) would result
      51                 :  *     in a coverage of mostly disjoint raster objects.
      52                 :  * 
      53                 :  * A table with c), d) or e) arrangements is said to have "regular
      54                 :  * blocking arrangement". This is:
      55                 :  *  - All raster tiles (table rows) have the same width and height.
      56                 :  *  - All tiles do not overlap and their upper left corners follow a 
      57                 :  *    regular block grid.
      58                 :  *  - The global extent of the raster is rectangular and not rotated.
      59                 :  *
      60                 :  * To know if a given raster table is expected to have regular blocking
      61                 :  * arrangement, there is a special table called RASTER_COLUMNS table,
      62                 :  * similar in concept to GEOMETRY_COLUMNS table for PostGIS, with a
      63                 :  * boolean field "regular_blocking". There is, however, no mechanism to 
      64                 :  * enforce (constrain) these criteria and adding, modifying or deleting a 
      65                 :  * row from the table might break this regular blocking, and the 
      66                 :  * regular_blocking attribute will not be automatically updated.
      67                 :  *
      68                 :  * NOTE:
      69                 :  *  There are many small functions in this class. Some of these functions
      70                 :  *  perform database queries. From the point of view of performance, this 
      71                 :  *  may be a bad idea, but from point of view of code manintenance, I think
      72                 :  *  is better. Anyway, the WKT Raster project is being developed at same 
      73                 :  *  time that this driver,and I think that is better to allow fast changes
      74                 :  *  in the code (easy to understand and to change) than performance, at 
      75                 :  *  this moment (August 2009)
      76                 :  *
      77                 :  * TODO:
      78                 :  *  - Eliminate working mode. We can determine if the raster has regular
      79                 :  *    blocking or not by querying RASTER_COLUMNS table.
      80                 :  *  - Allow non-regular blocking table arrangements (in general)
      81                 :  *  - Allow PQ connection string parameters in any order
      82                 :  *  - Update data blocks in SetProjection
      83                 :  *  - Update data blocks in SetGeoTransform
      84                 :  *  - Disable sequential scanning in OpenConnection in the database 
      85                 :  *    instance has support for GEOMETRY type (is a good idea?)
      86                 :  *  - In SetRasterProperties, if we can't create OGRGeometry from database,
      87                 :  *    we should "attack" directly the WKT representation of geometry, not
      88                 :  *    abort the program. For example, when pszProjectionRef is NULL
      89                 :  *   (SRID = -1), when poSR or prGeom are NULL...
      90                 :  *
      91                 :  *    Low priority:
      92                 :  *      - Add support for rotated images in SetRasterProperties
      93                 :  *      - Check if the tiles of a table REALLY have regular blocking 
      94                 :  *        arrangement.The fact that "regular_blocking" field in 
      95                 :  *        RASTER_COLUMNS table is set to TRUE doesn't proof it. Method 
      96                 :  *        TableHasRegularBlocking.
      97                 :  *
      98                 :  ************************************************************************
      99                 :  * Copyright (c) 2009, Jorge Arevalo, jorgearevalo@gis4free.org
     100                 :  *
     101                 :  * Permission is hereby granted, free of charge, to any person obtaining a
     102                 :  * copy of this software and associated documentation files (the 
     103                 :  * "Software"), to deal in the Software without restriction, including 
     104                 :  * without limitation the rights to use, copy, modify, merge, publish, 
     105                 :  * distribute, sublicense, and/or sell copies of the Software, and to 
     106                 :  * permit persons to whom the Software is furnished to do so, subject to 
     107                 :  * the following conditions:
     108                 :  *
     109                 :  * The above copyright notice and this permission notice shall be included
     110                 :  * in all copies or substantial portions of the Software.
     111                 :  *
     112                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     113                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
     114                 :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
     115                 :  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 
     116                 :  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
     117                 :  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
     118                 :  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     119                 :  ************************************************************************/
     120                 : 
     121                 : #include "wktraster.h"
     122                 : #include <stdlib.h>
     123                 : #include "ogr_api.h"
     124                 : #include "ogr_geometry.h"
     125                 : #include "gdal.h"
     126                 : #include "cpl_conv.h"
     127                 : #include "cpl_string.h"
     128                 : #include "gdal_priv.h"
     129                 : #include <math.h>
     130                 : #include <cpl_error.h>
     131                 : #include <ogr_core.h>
     132                 : 
     133                 : #ifdef _WIN32
     134                 : #define rint(x) floor((x) + 0.5)
     135                 : #endif
     136                 : 
     137                 : CPL_CVSID("$Id: wktrasterdataset.cpp 19624 2010-05-07 10:33:25Z jorgearevalo $");
     138                 : 
     139                 : CPL_C_START
     140                 : void GDALRegister_WKTRaster(void);
     141                 : 
     142                 : CPL_C_END
     143                 : 
     144                 : 
     145                 :     /**
     146                 :      * Constructor. Init the class properties with default values
     147                 :      */
     148               0 : WKTRasterDataset::WKTRasterDataset() {

     149               0 :     hPGconn = NULL;

     150               0 :     bCloseConnection = FALSE;

     151               0 :     pszSchemaName = NULL;

     152               0 :     pszTableName = NULL;

     153               0 :     pszRasterColumnName = NULL;

     154               0 :     pszWhereClause = NULL;

     155               0 :     bTableHasGISTIndex = FALSE;

     156               0 :     nVersion = 0;

     157               0 :     nBlockSizeX = 0;

     158               0 :     nBlockSizeY = 0;

     159               0 :     dfPixelSizeX = 0.0;

     160               0 :     dfPixelSizeY = 0.0;

     161               0 :     dfUpperLeftX = 0.0;

     162               0 :     dfUpperLeftY = 0.0;

     163               0 :     dfLowerRightX = 0.0;

     164               0 :     dfLowerRightY = 0.0;

     165               0 :     dfSkewX = 0.0;

     166               0 :     dfSkewY = 0.0;

     167               0 :     nSrid = -1;

     168               0 :     nOverviews = 0;

     169               0 :     papoWKTRasterOv = NULL;

     170               0 :     poOutdbRasterDS = NULL;

     171                 : 
     172                 :     // TO BE DELETED
     173               0 :     papoBlocks = NULL;

     174               0 :     nBlocks = 0;

     175                 :     
     176               0 : }

     177                 : 
     178                 :     /**
     179                 :      * Destructor. Frees allocated memory.
     180                 :      */
     181               0 : WKTRasterDataset::~WKTRasterDataset() {

     182               0 :     CPLFree(pszSchemaName);

     183               0 :     CPLFree(pszTableName);

     184               0 :     CPLFree(pszWhereClause);

     185               0 :     CPLFree(pszRasterColumnName);

     186                 : 
     187               0 :     if (nOverviews > 0) {

     188               0 :         for (int i = 0; i < nOverviews; i++) {

     189               0 :             delete papoWKTRasterOv[i];

     190               0 :             papoWKTRasterOv[i] = NULL;

     191                 :         }
     192                 : 
     193               0 :         CPLFree(papoWKTRasterOv);

     194                 :     }
     195                 : 
     196                 : 
     197               0 :     if (nBlocks > 0) {

     198               0 :         for(int i = 0; i < nBlocks; i++) {

     199               0 :             delete papoBlocks[i];

     200               0 :             papoBlocks[i] = NULL;

     201                 :         }
     202                 : 
     203               0 :         CPLFree(papoBlocks);

     204                 :     }
     205                 : 
     206                 :     /**
     207                 :      * bCloseConnection = TRUE for Dataset, FALSE for Overviews
     208                 :      */
     209               0 :     if (bCloseConnection == TRUE && hPGconn != NULL) {

     210               0 :         PQfinish(hPGconn);

     211               0 :         hPGconn = NULL;

     212                 :     }
     213                 : 
     214               0 :     if (poOutdbRasterDS != NULL) {

     215               0 :         GDALClose((GDALDatasetH)poOutdbRasterDS);

     216                 :     }
     217               0 : }

     218                 : 
     219                 : /**
     220                 :  * Check if the table has an index
     221                 :  * Parameters:
     222                 :  *  - PGconn *: pointer to connection
     223                 :  *  - const char *: table name
     224                 :  *  - const char *: table schema
     225                 :  * Output:
     226                 :  *  - GBool: TRUE if the table has an index, FALSE otherwise
     227                 :  */
     228                 : static
     229                 : GBool TableHasGISTIndex(PGconn * hPGconn, const char * pszTable,
     230               0 :         const char * pszSchema) {

     231                 : 
     232                 :     // Security checkings
     233               0 :     VALIDATE_POINTER1(hPGconn, "TableHasGISTIndex", FALSE);

     234               0 :     VALIDATE_POINTER1(pszTable, "TableHasGISTIndex", FALSE);

     235                 : 
     236                 : 
     237               0 :     CPLString osCommand;

     238               0 :     PGresult * hPGresult = NULL;

     239                 :     char * pszResultString;
     240               0 :     GBool bTableHasIndex = FALSE;

     241                 :     
     242                 :     /*****************************************************************
     243                 :      * Check if the table has an index in PostgreSQL system tables
     244                 :      *****************************************************************/
     245                 :     osCommand.Printf(
     246                 :             "SELECT relhasindex FROM pg_class, pg_attribute, pg_type, \
     247                 :             pg_namespace WHERE pg_namespace.nspname = '%s' and \
     248                 :             pg_namespace.oid = pg_class.relnamespace and \
     249                 :             pg_class.relname = '%s' and \
     250                 :             pg_class.oid = pg_attribute.attrelid and \
     251                 :         pg_attribute.atttypid = pg_type.oid and \
     252                 :             pg_type.typname = 'raster'",
     253               0 :            pszTable, pszSchema);

     254                 : 
     255               0 :     hPGresult = PQexec(hPGconn, osCommand.c_str());

     256               0 :     if (

     257                 :             hPGresult != NULL &&
     258                 :             PQresultStatus(hPGresult) == PGRES_TUPLES_OK &&
     259                 :             PQntuples(hPGresult) > 0
     260                 :             ) 
     261                 :     {
     262               0 :         pszResultString = PQgetvalue(hPGresult, 0, 0);

     263               0 :         if (pszResultString != NULL && CSLTestBoolean(pszResultString))

     264                 :         {
     265               0 :             bTableHasIndex = TRUE;

     266                 :         } 
     267                 :         else 
     268                 :         {
     269               0 :             bTableHasIndex = FALSE;

     270                 :         }
     271                 : 
     272                 :     } 
     273                 :     else 
     274                 :     {
     275               0 :        bTableHasIndex = FALSE;

     276                 :     }  
     277                 : 
     278               0 :     if (hPGresult)

     279               0 :         PQclear(hPGresult);

     280                 : 
     281               0 :     return bTableHasIndex;

     282                 : }
     283                 : 
     284                 : 
     285                 : /**
     286                 :  * Check if the RASTER_COLUMNS table exists
     287                 :  * Parameters:
     288                 :  *  - PGconn *: pointer to connection
     289                 :  * Output:
     290                 :  *  - GBool: TRUE if the table RASTER_COLUMNS does exist, FALSE otherwise
     291                 :  */
     292                 : static
     293               0 : GBool ExistsRasterColumnsTable(PGconn * hPGconn)

     294                 : {
     295               0 :     VALIDATE_POINTER1(hPGconn, "ExistsRasterColumnsTable", FALSE);

     296               0 :     PGresult * hPGresult = NULL;

     297               0 :     int nCount = 0;

     298               0 :     GBool bExistsRasterColumnsTable = FALSE;

     299               0 :     CPLString osCommand;

     300                 : 
     301                 :     /*********************************************************************
     302                 :      * Look for RASTER_COLUMNS table
     303                 :      *********************************************************************/
     304                 :     osCommand.Printf(
     305               0 :             "select count(pg_class.relname) from pg_class, pg_namespace \

     306                 :             where pg_class.relnamespace = pg_namespace.oid and \
     307                 :             pg_class.relname='raster_columns'");
     308               0 :     hPGresult = PQexec(hPGconn, osCommand.c_str());

     309               0 :     if (

     310                 :             hPGresult != NULL &&
     311                 :             PQresultStatus(hPGresult) == PGRES_TUPLES_OK &&
     312                 :             PQntuples(hPGresult) > 0
     313                 :             ) 
     314                 :     {
     315               0 :         nCount = atoi(PQgetvalue(hPGresult, 0, 0));

     316               0 :         if (nCount == 1)

     317                 :         {
     318               0 :             bExistsRasterColumnsTable = TRUE;

     319                 :         } 
     320                 :         else 
     321                 :         {
     322               0 :             bExistsRasterColumnsTable = FALSE;

     323                 :         }
     324                 : 
     325                 :     } 
     326                 :     else 
     327                 :     {
     328               0 :         bExistsRasterColumnsTable = FALSE;

     329                 :     }
     330                 : 
     331                 :     if (hPGresult);
     332               0 :         PQclear(hPGresult);

     333                 :         
     334               0 :     return bExistsRasterColumnsTable;

     335                 : }
     336                 : 
     337                 : 
     338                 : /**
     339                 :  * Check if exists an overviews table
     340                 :  * Parameters:
     341                 :  *  - PGconn *: pointer to connection
     342                 :  * Output:
     343                 :  *  - GBool: TRUE if the table RASTER_OVERVIEWS does exist, FALSE otherwise
     344                 :  */
     345                 : static
     346               0 : GBool ExistsOverviewsTable(PGconn * hPGconn) 

     347                 : {
     348               0 :     VALIDATE_POINTER1(hPGconn, "ExistsRasterOverviewsTable", FALSE);

     349               0 :     PGresult * hPGresult = NULL;

     350               0 :     int nCount = 0;

     351               0 :     GBool bExistsRasterOverviewsTable = FALSE;

     352               0 :     CPLString osCommand;

     353                 : 
     354                 :     /*********************************************************************
     355                 :      * Look for RASTER_COLUMNS table
     356                 :      *********************************************************************/
     357                 :     osCommand.Printf(
     358               0 :             "select count(pg_class.relname) from pg_class, pg_namespace \

     359                 :             where pg_class.relnamespace = pg_namespace.oid and \
     360                 :             pg_class.relname='raster_overviews'");
     361               0 :     hPGresult = PQexec(hPGconn, osCommand.c_str());

     362               0 :     if (

     363                 :             hPGresult != NULL &&
     364                 :             PQresultStatus(hPGresult) == PGRES_TUPLES_OK &&
     365                 :             PQntuples(hPGresult) > 0
     366                 :             ) 
     367                 :     {
     368               0 :         nCount = atoi(PQgetvalue(hPGresult, 0, 0));

     369               0 :         if (nCount == 1)

     370                 :         {
     371               0 :             bExistsRasterOverviewsTable = TRUE;

     372                 :         } 
     373                 :         else 
     374                 :         {
     375               0 :             bExistsRasterOverviewsTable = FALSE;

     376                 :         }
     377                 : 
     378                 :     } 
     379                 :     else 
     380                 :     {
     381               0 :         bExistsRasterOverviewsTable = FALSE;

     382                 :     }
     383                 : 
     384                 :     if (hPGresult);
     385               0 :         PQclear(hPGresult);

     386                 :         
     387               0 :     return bExistsRasterOverviewsTable;

     388                 : }
     389                 : 
     390                 : 
     391                 : /**
     392                 :  * Check if the table has regular_blocking constraint.
     393                 :  * NOTE: From now, only tables with regular_blocking are allowed
     394                 :  * Parameters:
     395                 :  *  - PGconn *: pointer to connection
     396                 :  *  - const char *: table name
     397                 :  *  - const char *: raster column name
     398                 :  *  - const char *: schema name
     399                 :  * Returns:
     400                 :  *  - GBool: TRUE if the table has regular_blocking constraint, FALSE 
     401                 :  *          otherwise
     402                 :  */
     403                 : static
     404                 : GBool TableHasRegularBlocking(PGconn * hPGconn, const char * pszTable,
     405               0 :         const char * pszColumn, const char * pszSchema) 

     406                 : {
     407                 : 
     408                 :     /* Check input parameters */
     409               0 :     VALIDATE_POINTER1(hPGconn, "TableHasRegularBlocking", FALSE);

     410               0 :     VALIDATE_POINTER1(pszTable, "TableHasRegularBlocking", FALSE);

     411               0 :     VALIDATE_POINTER1(pszColumn, "TableHasRegularBlocking", FALSE);

     412                 : 
     413               0 :     CPLString osCommand;

     414               0 :     PGresult * hPGresult = NULL;

     415                 :     char * pszResultString;
     416               0 :     GBool bTableHasRegularBlocking = FALSE;

     417                 : 
     418                 : 
     419                 :     /**********************************************************************
     420                 :      * Look for regular_blocking in RASTER_COLUMNS table
     421                 :      *********************************************************************/
     422                 :     osCommand.Printf(
     423                 :             "SELECT  regular_blocking FROM raster_columns WHERE \
     424                 :             r_table_name = '%s' and r_column = '%s' and \
     425                 :             r_table_schema = '%s'",
     426               0 :             pszTable, pszColumn, pszSchema);

     427                 : 
     428               0 :     hPGresult = PQexec(hPGconn, osCommand.c_str());

     429               0 :     if (hPGresult != NULL && PQresultStatus(hPGresult) == PGRES_TUPLES_OK 

     430                 :             && PQntuples(hPGresult) > 0) 
     431                 :     {
     432               0 :         pszResultString = PQgetvalue(hPGresult, 0, 0);

     433               0 :         if (pszResultString != NULL && CSLTestBoolean(pszResultString))

     434                 :         {
     435               0 :             bTableHasRegularBlocking = TRUE;

     436                 :         } 
     437                 :         else 
     438                 :         {
     439               0 :             bTableHasRegularBlocking = FALSE;

     440                 :         }
     441                 : 
     442                 : 
     443                 :     } 
     444                 :     else 
     445                 :     {
     446               0 :         bTableHasRegularBlocking = FALSE;

     447                 :     }
     448                 : 
     449               0 :     if (hPGresult != NULL)

     450               0 :         PQclear(hPGresult);

     451                 : 
     452               0 :     return bTableHasRegularBlocking;

     453                 : }
     454                 : 
     455                 : /**
     456                 :  * Get the name of the column of type raster
     457                 :  * Parameters:
     458                 :  *  PGconn *: pointer to connection
     459                 :  *      const char *: schema name
     460                 :  *  const char *: table name
     461                 :  * Output:
     462                 :  *  char *: The column name, or NULL if doesn't exist
     463                 :  */
     464                 : static
     465                 : char * GetWKTRasterColumnName(PGconn * hPGconn, const char * pszSchemaName,
     466               0 :         const char * pszTable) {

     467                 : 
     468                 :     // Security checkings
     469               0 :     VALIDATE_POINTER1(hPGconn, "GetWKTRasterColumnName", NULL);

     470               0 :     VALIDATE_POINTER1(pszTable, "GetWKTRasterColumnName", NULL);

     471                 : 
     472               0 :     CPLString osCommand;

     473               0 :     PGresult * hPGresult = NULL;

     474                 :     char * pszResultString;
     475                 : 
     476                 :   
     477                 :     /************************************************************
     478                 :      * Get the attribute name of type 'raster' of the table
     479                 :      ************************************************************/
     480                 :     osCommand.Printf(
     481                 :             "SELECT attname \
     482                 :             FROM pg_class, pg_attribute, pg_type, pg_namespace \
     483                 :             WHERE \
     484                 :     pg_namespace.nspname = '%s' and \
     485                 :     pg_namespace.oid = pg_class.relnamespace and \
     486                 :     pg_class.relname = '%s' and \
     487                 :     pg_class.oid = pg_attribute.attrelid and \
     488                 :     pg_attribute.atttypid = pg_type.oid and \
     489                 :     pg_type.typname = 'raster'",
     490               0 :             pszSchemaName, pszTable);

     491                 : 
     492               0 :     hPGresult = PQexec(hPGconn, osCommand.c_str());

     493               0 :     if (

     494                 :             hPGresult != NULL &&
     495                 :             PQresultStatus(hPGresult) == PGRES_TUPLES_OK &&
     496                 :             PQntuples(hPGresult) > 0
     497                 :             ) {
     498               0 :         pszResultString = CPLStrdup(PQgetvalue(hPGresult, 0, 0));

     499               0 :         PQclear(hPGresult);

     500                 : 
     501                 :     } else {
     502               0 :         if (hPGresult != NULL)

     503               0 :             PQclear(hPGresult);

     504               0 :         pszResultString = NULL;

     505                 :     }
     506                 : 
     507                 : 
     508               0 :     return pszResultString;

     509                 : 
     510                 : }
     511                 : 
     512                 : /**
     513                 :  * Open a database connection and perform some security checkings
     514                 :  * Parameters:
     515                 :  *  const char *: Connection string
     516                 :  * Output:
     517                 :  *  PGconn *: pointer to object connection, or NULL it there was a problem
     518                 :  */
     519                 : static
     520               1 : PGconn * OpenConnection(const char *pszConnectionString) {

     521                 : 
     522                 :     // Security checkings
     523               1 :     VALIDATE_POINTER1(pszConnectionString, "OpenConnection", NULL);

     524                 :    
     525               1 :     PGconn * hPGconn = NULL;

     526               1 :     PGresult * hPGresult = NULL;

     527                 : 
     528                 : 
     529                 :     /********************************************************
     530                 :      *    Connect with database
     531                 :      ********************************************************/
     532               1 :     hPGconn = PQconnectdb(pszConnectionString + 3);

     533               1 :     if (hPGconn == NULL || PQstatus(hPGconn) == CONNECTION_BAD) {

     534                 :         CPLError(CE_Failure, CPLE_AppDefined, "PGconnectcb failed.\n%s",
     535               1 :                 PQerrorMessage(hPGconn));

     536               1 :         PQfinish(hPGconn);

     537               1 :         return NULL;

     538                 :     }
     539                 : 
     540                 :     /*****************************************************************
     541                 :      *  Test to see if this database instance has support for the
     542                 :      *  PostGIS Geometry type.
     543                 :      *  TODO: If so, disable sequential scanning so we will get the
     544                 :      *  value of the gist indexes. (is it a good idea?)
     545                 :      *****************************************************************/
     546                 :     hPGresult = PQexec(hPGconn,
     547               0 :             "SELECT oid FROM pg_type WHERE typname = 'geometry'");

     548               0 :     if (

     549                 :             hPGresult == NULL ||
     550                 :             PQresultStatus(hPGresult) != PGRES_TUPLES_OK ||
     551                 :             PQntuples(hPGresult) <= 0
     552                 :             ) {
     553                 :         CPLError(CE_Failure, CPLE_AppDefined,
     554               0 :                 "Can't find geometry type, is Postgis correctly installed ?\n");

     555               0 :         if (hPGresult)

     556               0 :             PQclear(hPGresult);

     557               0 :         PQfinish(hPGconn);

     558               0 :         hPGconn = NULL;

     559                 : 
     560                 :     }
     561                 : 
     562               0 :     return hPGconn;

     563                 : }
     564                 : 
     565                 : /**
     566                 :  * Extract a field from the connection string:
     567                 :  * PG:[host='<host>'] [user='<user>'] [password='<password>']
     568                 :  * dbname='<dbname>' table='<raster_table>' [mode='<working_mode>'
     569                 :  * where='<where_clause>']
     570                 :  * The idea is to extract the fields that PQconnect function doesn't accept
     571                 :  * (this is, 'table', 'mode' and 'where')
     572                 :  *
     573                 :  * Parameters:
     574                 :  *  char **: pointer to connection string, to be modified
     575                 :  *  char *: field init (ex.: "where=", "table=")
     576                 :  * Output:
     577                 :  *  char *: The field (where clause or table name) of the connection string
     578                 :  *  if everything works fine, NULL otherwise
     579                 :  */
     580                 : static
     581               3 : char * ExtractField(char ** ppszConnectionString, const char * pszFieldInit) {

     582                 : 
     583                 :     // Security checkings
     584               3 :     VALIDATE_POINTER1(ppszConnectionString, "ExtractField", NULL);

     585               3 :     VALIDATE_POINTER1(*ppszConnectionString, "ExtractField", NULL);

     586               3 :     VALIDATE_POINTER1(pszFieldInit, "ExtractField", NULL);

     587                 : 
     588               3 :     char * pszField = NULL;

     589               3 :     char * pszStart = NULL;

     590                 : 
     591                 : 
     592                 :     /************************************************************************
     593                 :      * Get the value of the field to extract, and delete the whole field
     594                 :      * from the connection string
     595                 :      ************************************************************************/
     596               3 :     int nFieldInitLen = strlen(pszFieldInit);

     597                 : 
     598                 :     /*
     599                 :      * Get the initial position of the field in the string
     600                 :      */
     601               3 :     pszStart = strstr(*ppszConnectionString, pszFieldInit); 

     602               3 :     if (pszStart == NULL)

     603               1 :         return NULL;

     604                 :     
     605               2 :     int bHasQuote = pszStart[nFieldInitLen] == '\'';

     606                 : 
     607                 :     // Copy the field of the connection string to another var
     608               2 :     pszField = CPLStrdup(pszStart + nFieldInitLen + bHasQuote);

     609               2 :     char* pszEndField = strchr(pszField, (bHasQuote) ? '\'' : ' ');

     610               2 :     if (pszEndField)

     611                 :     {
     612               2 :         *pszEndField = '\0';

     613                 :         char* pszEnd = pszStart + nFieldInitLen + bHasQuote +
     614               2 :             (pszEndField - pszField) + 1;

     615               2 :         memmove(pszStart, pszEnd, strlen(pszEnd) + 1);

     616                 :     }
     617                 :     else
     618                 :         // Delete the field's part from the connection string
     619               0 :         *pszStart = '\0';

     620                 : 
     621               2 :     return pszField;

     622                 : }
     623                 : 
     624                 : /**
     625                 :  * Populate the georeference information fields of dataset
     626                 :  * Input:
     627                 :  * Output:
     628                 :  *      CPLErr: CE_None if the fields are populated, CE_Failure otherwise
     629                 :  */
     630               0 : CPLErr WKTRasterDataset::SetRasterProperties()

     631                 : {
     632               0 :     CPLString osCommand;

     633               0 :     PGresult * hPGresult = NULL;

     634                 :     char * pszExtent;
     635               0 :     OGRSpatialReference * poSR = NULL;

     636               0 :     OGRGeometry * poGeom = NULL;

     637               0 :     OGRErr OgrErr = OGRERR_NONE;

     638               0 :     OGREnvelope * poE = NULL;

     639                 :     char * pszProjectionRef;   
     640                 : 
     641                 :     /*********************************************************************
     642                 :      * The raster table could contain several images with different
     643                 :      * georeference information, or even doesn't contain georeference at
     644                 :      * all. So, we first need to check if the raster table has regular
     645                 :      * blocking structure or not
     646                 :      *********************************************************************/
     647               0 :     if (bTableHasRegularBlocking)

     648                 :     {
     649                 :         /**
     650                 :          * With a WHERE clause, we can get one or more rows, but if 
     651                 :          * regular blocking is expected for this table, all the rows
     652                 :          * (tiles) have the same width and height, and their upper left
     653                 :          * corners follow a regular block grid. So, we can get the first
     654                 :          * row to get these values.
     655                 :          * xxx jorgearevalo: the same srid and pixel size too?
     656                 :          */
     657               0 :         if (pszWhereClause != NULL)

     658                 :         {
     659                 :             osCommand.Printf(
     660               0 :                 "SELECT st_srid(rast), st_skewx(rast), st_skewy(rast), \

     661                 :                 st_pixelsizex(rast), st_pixelsizey(rast) FROM %s.%s \
     662                 :                 WHERE %s", pszSchemaName, pszTableName, pszWhereClause);
     663                 :         }
     664                 : 
     665                 :         /**
     666                 :          * Without a WHERE clause, we don't have a row filter, but the
     667                 :          * principle is the same, as regular blocking is expected for this
     668                 :          * table.
     669                 :          */
     670                 :         else
     671                 :         {
     672                 :              osCommand.Printf(
     673                 :                 "SELECT st_srid(rast), st_skewx(rast), st_skewy(rast),\
     674                 :                 st_pixelsizex(rast), st_pixelsizey(rast) FROM %s.%s", 
     675               0 :                 pszSchemaName, pszTableName);

     676                 :         }
     677                 : 
     678               0 :         hPGresult = PQexec(hPGconn, osCommand.c_str());

     679               0 :         if (hPGresult != NULL && 

     680                 :                 PQresultStatus(hPGresult) == PGRES_TUPLES_OK &&
     681                 :                 PQntuples(hPGresult) > 0)
     682                 :         {
     683                 : 
     684                 :             /**
     685                 :              * Get most of the raster properties
     686                 :              **/
     687               0 :             nSrid = atoi(PQgetvalue(hPGresult, 0, 0));

     688               0 :             dfSkewX = atof(PQgetvalue(hPGresult, 0, 1));

     689               0 :             dfSkewY = atof(PQgetvalue(hPGresult, 0, 2));

     690               0 :             dfPixelSizeX = atof(PQgetvalue(hPGresult, 0, 3));

     691               0 :             dfPixelSizeY = atof(PQgetvalue(hPGresult, 0, 4));

     692                 : 
     693               0 :             PQclear(hPGresult);

     694                 :             
     695                 :             /**
     696                 :              * The rest of the properties are gotten from
     697                 :              * RASTER_COLUMNS table
     698                 :              * TODO: we don't need st_astext, should be enough with
     699                 :              * extent. Study it.
     700                 :              */
     701                 :             osCommand.Printf(
     702                 :                     "SELECT blocksize_x, blocksize_y, st_astext(extent) \
     703                 :                     FROM raster_columns WHERE r_table_schema = '%s' AND \
     704                 :                     r_table_name = '%s' AND r_column = '%s'",
     705               0 :                     pszSchemaName, pszTableName, pszRasterColumnName);

     706                 :        
     707               0 :             hPGresult = PQexec(hPGconn, osCommand.c_str());

     708               0 :             if (hPGresult != NULL && 

     709                 :                 PQresultStatus(hPGresult) == PGRES_TUPLES_OK &&
     710                 :                 PQntuples(hPGresult) > 0)
     711                 :             {
     712                 :                 nBlockSizeX = (PQgetvalue(hPGresult, 0, 0)) ? 
     713                 :                     atoi(PQgetvalue(hPGresult, 0, 0)) :
     714               0 :                     0;

     715                 :                 nBlockSizeY = (PQgetvalue(hPGresult, 0, 1)) ?
     716                 :                     atoi(PQgetvalue(hPGresult, 0, 1)) :
     717               0 :                     0;

     718                 : 
     719                 :                 /**
     720                 :                  * Be careful: The extent coordinates are projected
     721                 :                  * coordinates, unless the raster covered by extent
     722                 :                  * doesn't have georeference information (srid = -1)
     723                 :                  **/
     724               0 :                 pszExtent = CPLStrdup(PQgetvalue(hPGresult, 0, 2));

     725                 : 
     726               0 :                 PQclear(hPGresult);

     727                 :                                              
     728                 :                 /**
     729                 :                  * Construct a Geometry Object based on raster extent
     730                 :                  */                    
     731               0 :                 pszProjectionRef = (char *) GetProjectionRef();           

     732               0 :                 poSR = new OGRSpatialReference(pszProjectionRef);

     733                 :                 OgrErr = OGRGeometryFactory::createFromWkt(
     734               0 :                         &pszExtent, poSR, &poGeom);

     735               0 :                 if (OgrErr != OGRERR_NONE) 

     736                 :                 {
     737                 :                     CPLError(CE_Failure, CPLE_AppDefined,
     738               0 :                         "Couldn't get WKT Raster extent from database");

     739                 :                     //CPLFree(pszExtent);
     740                 :                     //CPLFree(pszProjectionRef);
     741                 : 
     742               0 :                     return CE_Failure;

     743                 :                 }         
     744                 :                 
     745               0 :                 poE = new OGREnvelope();

     746               0 :                 poGeom->getEnvelope(poE);

     747                 : 
     748                 :                 /**
     749                 :                  * Get the rest of raster properties from this object
     750                 :                  */
     751                 :                 nRasterXSize = (int)
     752               0 :                     fabs(rint((poE->MaxX - poE->MinX) / dfPixelSizeX));

     753                 :                 nRasterYSize = (int)
     754               0 :                     fabs(rint((poE->MaxY - poE->MinY) / dfPixelSizeY));

     755                 :                 
     756                 :                 /**
     757                 :                  * TODO: Review this. Is a good algorithm?
     758                 :                  * If the pixel size Y is negative, we can assume the raster's
     759                 :                  * reference system uses cartesian coordinates, in which the
     760                 :                  * origin is in lower-left corner, while the origin in an image
     761                 :                  * is un upper-left corner. In this case, the upper left Y value
     762                 :                  * will be MaxY from the envelope. Otherwise, it will be MinY.
     763                 :                  **/                
     764               0 :                 dfUpperLeftX = poE->MinX;

     765               0 :                 if (dfPixelSizeY >= 0.0) 

     766               0 :                     dfUpperLeftY = poE->MinY;

     767                 :                 else
     768               0 :                     dfUpperLeftY = poE->MaxY;

     769                 :               
     770                 :                 /**
     771                 :                  * TODO: pszExtent is modified by createFromWkt, so, we 
     772                 :                  * can't free it. What should we do?
     773                 :                  * And something happens with pszProjectionRef too
     774                 :                  */
     775                 :                 //CPLFree(pszExtent);
     776                 :                 //CPLFree(pszProjectionRef);                
     777                 :             }
     778                 : 
     779                 :             else
     780                 :             {
     781                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     782               0 :                         "Couldn't get raster dimensions from database");

     783               0 :                 if (hPGresult)

     784               0 :                     PQclear(hPGresult);

     785                 :                
     786               0 :                 return CE_Failure;

     787                 :             }
     788                 : 
     789                 :         }
     790                 : 
     791                 :         else
     792                 :         {
     793                 :             CPLError(CE_Failure, CPLE_OpenFailed,
     794               0 :                     "Couldn't fetch raster information.");

     795               0 :             return CE_Failure;

     796                 :         }
     797                 :     }
     798                 : 
     799                 :     /********************************************************************
     800                 :      * Table with non regular blocking arrangement. Still under
     801                 :      * development
     802                 :      ********************************************************************/
     803                 :     else
     804                 :     {
     805                 :             CPLError(CE_Failure, CPLE_AppDefined,
     806               0 :                     "Table with non regular blocking arrangement.\

     807                 :                     This feature is not supported yet\n");
     808               0 :             return CE_Failure;

     809                 : 
     810                 :     }
     811                 : 
     812               0 :     return CE_None;

     813                 : }
     814                 : 
     815                 : 
     816                 : /**
     817                 :  * Explode a string representing an array into an array of strings. The input
     818                 :  * string has this format: {element1,element2,element3,....,elementN}
     819                 :  * Parameters:
     820                 :  *  - const char *: a string representing an array
     821                 :  *  - int *: pointer to an int that will contain the number of elements
     822                 :  * Returns:
     823                 :  *  char **: An array of strings, one per element. Must be freed with CSLDestroy
     824                 :  */
     825                 : char ** WKTRasterDataset::ExplodeArrayString(
     826               0 :         const char * pszPQarray, int * pnNumberOfElements) {

     827                 : 
     828                 :     // integrity checkings
     829               0 :     if (

     830                 :             pszPQarray == NULL ||
     831                 :             pszPQarray[0] != '{' ||
     832                 :             pszPQarray[strlen(pszPQarray) - 1] != '}'
     833                 :             ) {
     834               0 :         if (pnNumberOfElements)

     835               0 :             *pnNumberOfElements = 0;

     836               0 :         return NULL;

     837                 :     }
     838                 :     
     839               0 :     char* pszTemp = CPLStrdup(pszPQarray + 1);

     840               0 :     pszTemp[strlen(pszTemp) - 1] ='\0';

     841               0 :     char** papszRet = CSLTokenizeString2( pszTemp, ",", 0 );

     842               0 :     CPLFree(pszTemp);

     843                 :     
     844               0 :     if (pnNumberOfElements)

     845               0 :         *pnNumberOfElements = CSLCount(papszRet);

     846               0 :     return papszRet;

     847                 : }
     848                 : 
     849                 : 
     850                 : /**
     851                 :  * Implode an array of strings, to transform it into a PostgreSQL-style
     852                 :  * array, with this format: {element1,element2,element3,....,elementN}
     853                 :  * Input:
     854                 :  *  char **: An array of strings, one per element
     855                 :  *  int: An int that contains the number of elements
     856                 :  * Output:
     857                 :  *  const char *: a string representing an array
     858                 :  */
     859               0 : char * WKTRasterDataset::ImplodeStrings(char ** papszElements, int nElements)

     860                 : {
     861               0 :     VALIDATE_POINTER1(papszElements, "ImplodeStrings", NULL);

     862                 : 
     863                 :     
     864               0 :     char * pszPQarray = NULL;

     865                 :     char * ptrString;
     866                 :     char szTemp[1024];
     867               0 :     unsigned int nCharsCopied = 0;

     868               0 :     unsigned int nNumberOfCommas = 0;

     869               0 :     unsigned int nNumAvailableBytes = 0;

     870               0 :     int nPosOpeningBracket = 0;

     871               0 :     int nPosClosingBracket = 0;

     872                 : 
     873                 :     /**************************************************************************
     874                 :      * Array for the string. We could allocate memory for all the elements of
     875                 :      * the array, plus commas and brackets, but 1024 bytes should be enough to
     876                 :      * store small values, and the method is faster in this way
     877                 :      **************************************************************************/
     878               0 :     pszPQarray = (char *)CPLCalloc(1024, sizeof(char));

     879               0 :     VALIDATE_POINTER1(pszPQarray, "ImplodeStrings", NULL);

     880                 : 
     881                 : 
     882                 :     // empty string
     883               0 :     if (nElements <= 0) {

     884               0 :         nPosOpeningBracket = 0;

     885               0 :         nPosClosingBracket = 1;

     886                 :     }
     887                 : 
     888                 :     // Without commas
     889               0 :     else if (nElements == 1) {

     890               0 :         nPosOpeningBracket = 0;

     891               0 :         nCharsCopied = MIN(1024, strlen(papszElements[0]));

     892                 :         memcpy(pszPQarray + sizeof(char),
     893               0 :                 papszElements[0], nCharsCopied*sizeof(char));

     894                 : 
     895               0 :         nPosClosingBracket = nCharsCopied + sizeof(char);

     896                 :     }
     897                 : 
     898                 :     // loop the array and create the string
     899                 :     else {
     900               0 :         nPosOpeningBracket = 0;

     901                 : 
     902               0 :         nNumberOfCommas = nElements - 1;

     903               0 :         nNumAvailableBytes = 1024 - (2 + nNumberOfCommas) * sizeof(char);

     904                 : 
     905                 :         // This should NEVER happen, it's really difficult...
     906               0 :         if (nNumAvailableBytes < 2) {

     907                 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     908               0 :                     "Sorry, couldn't allocate enough space for PQ array");

     909               0 :             CPLFree(pszPQarray);

     910                 :                    
     911               0 :             return NULL;

     912                 :         }
     913                 : 
     914                 :         // ptrString will move over the output string
     915               0 :         ptrString = pszPQarray + sizeof(char);

     916                 : 
     917               0 :         for(int i = 0; i < nElements; i++) {

     918                 : 
     919                 :             // Check if element really exists
     920               0 :             if (papszElements[i] == NULL) {

     921                 :                 // one less comma, more space available
     922               0 :                 nNumAvailableBytes += sizeof(char);

     923               0 :                 continue;

     924                 :             }
     925                 : 
     926                 :             // Copy the element to output string
     927                 :             else {
     928               0 :                 memset(szTemp, '\0', 1024*sizeof(char));

     929                 : 
     930                 :                 // We can copy, at most, the number of available bytes
     931               0 :                 nCharsCopied = MIN(strlen(papszElements[i]), nNumAvailableBytes);

     932               0 :                 memcpy(szTemp, papszElements[i], nCharsCopied * sizeof(char));

     933                 : 
     934                 :                 // Copy element to end string
     935               0 :                 memcpy(ptrString, szTemp, strlen(szTemp) * sizeof(char));

     936               0 :                 ptrString += strlen(szTemp) * sizeof(char);

     937                 :                 
     938                 :                 // No last element, add comma
     939               0 :                 if (i < nElements - 1) {

     940                 :                     // If we don't have space for more elements, break
     941               0 :                     if (nNumAvailableBytes == 1) {

     942               0 :                         break;

     943                 :                     }
     944                 : 
     945                 :                     // Add comma
     946               0 :                     ptrString[0] = ',';

     947               0 :                     ptrString += sizeof(char);

     948                 :                 }
     949                 :             }
     950                 :         }
     951                 : 
     952               0 :         nPosClosingBracket = ptrString - pszPQarray;

     953                 :     }
     954                 : 
     955                 :     // put brackets and return
     956               0 :     pszPQarray[nPosOpeningBracket] = '{';

     957               0 :     pszPQarray[nPosClosingBracket] = '}';

     958               0 :     return pszPQarray;

     959                 : }
     960                 : 
     961                 : /**
     962                 :  * Method: Open
     963                 :  * Open a connection wiht PostgreSQL. The connection string will have this
     964                 :  * format:
     965                 :  *  PG:[host='<host>]' user='<user>' [password='<password>]'
     966                 :  *      dbname='<dbname>' table='<raster_table>' [mode='working_mode'
     967                 :  *      where='<where_clause>'].
     968                 :  * All the connection string, apart from table='table_name', where='sql_where'
     969                 :  * and mode ='working_mode' is PQconnectdb-valid.
     970                 :  *
     971                 :  *  NOTE: The table name can't include the schema in the form
     972                 :  *      <schema>.<table_name>,
     973                 :  *  and this is a TODO task.
     974                 :  * Parameters:
     975                 :  *  - GDALOpenInfo *: pointer to a GDALOpenInfo structure, with useful
     976                 :  *                  information for Dataset
     977                 :  * Returns:
     978                 :  *  - GDALDataset *: pointer to a new GDALDataset instance on success,
     979                 :  *                  NULL otherwise
     980                 :  */
     981            9507 : GDALDataset * WKTRasterDataset::Open(GDALOpenInfo * poOpenInfo) {

     982            9507 :     GBool bTableHasIndex = FALSE;

     983            9507 :     GBool bExistsOverviewsTable = FALSE;

     984            9507 :     char * pszRasterColumnName = NULL;

     985            9507 :     char * pszSchemaName = NULL;

     986            9507 :     char * pszTableName = NULL;

     987            9507 :     char * pszWhereClause = NULL;

     988            9507 :     char * pszConnectionString = NULL;

     989            9507 :     WKTRasterDataset * poDS = NULL;

     990            9507 :     PGconn * hPGconn = NULL;

     991            9507 :     PGresult * hPGresult = NULL;

     992            9507 :     CPLString osCommand;

     993            9507 :     char * pszArrayPixelTypes = NULL;

     994            9507 :     char * pszArrayNodataValues = NULL;

     995            9507 :     char ** papszPixelTypes = NULL;

     996            9507 :     char ** papszNodataValues = NULL;

     997            9507 :     GDALDataType hDataType = GDT_Byte;

     998            9507 :     double dfNoDataValue = 0.0;

     999            9507 :     int nCountNoDataValues = 0;

    1000            9507 :     char ** papszTokenizedStr = NULL;

    1001                 :     const char * pszTmp;
    1002                 : 
    1003                 : 
    1004                 :     /********************************************************
    1005                 :      *               Security checkings
    1006                 :      ********************************************************/
    1007            9507 :     if (

    1008                 :             poOpenInfo->pszFilename == NULL ||
    1009                 :             !EQUALN(poOpenInfo->pszFilename, "PG:", 3)
    1010                 :             ) {
    1011                 :         /**
    1012                 :          * Drivers must quietly return NULL if the passed file is not of 
    1013                 :          * their format. They should only produce an error if the file 
    1014                 :          * does appear to be of their supported format, but for some 
    1015                 :          * reason, unsupported or corrupt
    1016                 :          */
    1017            9506 :         return NULL;

    1018                 :     }
    1019                 : 
    1020                 : 
    1021                 :     /*************************************************
    1022                 :      * Check GEOS library existence
    1023                 :      *************************************************/
    1024               1 :     if (OGRGeometryFactory::haveGEOS() == FALSE) {

    1025                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1026               0 :                 "Couldn't find GEOS library installed");

    1027               0 :         return NULL;

    1028                 :     }
    1029                 : 
    1030                 : 
    1031                 :     /********************************************************************
    1032                 :    * Extract schema name, table name and where clause. Then, reconstruct 
    1033                 :    * connection string without these fields
    1034                 :      ********************************************************************/
    1035               1 :     pszConnectionString = CPLStrdup(poOpenInfo->pszFilename);

    1036               1 :     pszSchemaName = ExtractField(&pszConnectionString, "schema=");

    1037               1 :   if (pszSchemaName == NULL)

    1038                 :   {
    1039               0 :     pszSchemaName = (char *)CPLCalloc(strlen("public"), sizeof(char));

    1040               0 :     if (pszSchemaName == NULL)

    1041                 :     {
    1042                 :       CPLError(CE_Failure, CPLE_OutOfMemory,
    1043               0 :             "Memory error allocating space for schema name");

    1044               0 :       return NULL;

    1045                 :     }
    1046               0 :     strcpy(pszSchemaName, "public");

    1047                 :   }
    1048               1 :   pszTableName = ExtractField(&pszConnectionString, "table=");

    1049               1 :   if (pszTableName == NULL)

    1050                 :   {        
    1051                 :     CPLError(CE_Failure, CPLE_AppDefined,
    1052               0 :           "Couldn't find table. Is connection string in the \

    1053                 :             format PG:\"host=<host> user=<user> password=<password> \
    1054                 :             dbname=<dbname> table=<raster_table> [schema=<schema>] \
    1055                 :             [where=<where_clause>]\"?\n");
    1056               0 :         CPLFree(pszSchemaName);

    1057               0 :     return NULL;  

    1058                 :   }
    1059                 : 
    1060               1 :     pszWhereClause = ExtractField(&pszConnectionString, "where=");

    1061                 : 
    1062                 :     /********************************************************
    1063                 :      *    Open a database connection
    1064                 :      ********************************************************/
    1065               1 :     hPGconn = OpenConnection(pszConnectionString);

    1066                 :     
    1067               1 :     CPLFree(pszConnectionString);

    1068               1 :     pszConnectionString = NULL;

    1069                 : 
    1070               1 :     if (hPGconn == NULL) 

    1071                 :     {
    1072                 : 
    1073               1 :         CPLFree(pszTableName);

    1074               1 :         CPLFree(pszSchemaName);

    1075               1 :         CPLFree(pszWhereClause);

    1076                 : 
    1077               1 :         return NULL;

    1078                 :     }
    1079                 : 
    1080                 :     
    1081                 :     /************************************************
    1082                 :      * Check if the RASTER_COLUMNS table does exist
    1083                 :      ************************************************/
    1084               0 :     if (ExistsRasterColumnsTable(hPGconn) == FALSE)  

    1085                 :     {
    1086                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1087               0 :                 "Couldn't find RASTER_COLUMNS table. Please, check WKT\

    1088                 :                 Raster extension is properly installed");
    1089                 : 
    1090               0 :         PQfinish(hPGconn);

    1091               0 :         CPLFree(pszTableName);

    1092               0 :         CPLFree(pszSchemaName);

    1093               0 :         CPLFree(pszWhereClause);

    1094                 : 
    1095               0 :         return NULL;

    1096                 :     }
    1097                 : 
    1098                 : 
    1099                 : 
    1100                 :     /******************************************************
    1101                 :      * Check if the table has a column of the type raster
    1102                 :      ******************************************************/
    1103                 :     pszRasterColumnName = GetWKTRasterColumnName(hPGconn, pszSchemaName,
    1104               0 :             pszTableName);

    1105               0 :     if (pszRasterColumnName == NULL) 

    1106                 :     {
    1107                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1108                 :                 "The table %s.%s doesn't exist or doesn't have a WKT Raster column\n",
    1109               0 :                 pszSchemaName, pszTableName);

    1110               0 :         PQfinish(hPGconn);

    1111               0 :         CPLFree(pszTableName);

    1112               0 :         CPLFree(pszSchemaName);

    1113               0 :         CPLFree(pszWhereClause);

    1114                 : 
    1115               0 :         return NULL;

    1116                 :     }
    1117                 : 
    1118                 : 
    1119                 :     /****************************************************
    1120                 :      *  Check if the table has regular_blocking
    1121                 :      *  constraint enabled. Currently only regular_blocking 
    1122                 :      * tables are allowed.
    1123                 :      *
    1124                 :      *  TODO: The fact that "regular_blocking"
    1125                 :      *  is set to TRUE doesn't mean that all the
    1126                 :      *  tiles read are regular. Need to check it
    1127                 :      ****************************************************/
    1128               0 :     if (TableHasRegularBlocking(hPGconn, pszTableName, 

    1129                 :         pszRasterColumnName, pszSchemaName) == FALSE)
    1130                 :     {
    1131                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1132                 :                 "Table %s.%s doesn't seem to have regular blocking \
    1133                 :                 arrangement. Only tables with regular blocking \
    1134                 :                 arrangement can  be read\n",
    1135               0 :                 pszSchemaName, pszTableName);

    1136               0 :         PQfinish(hPGconn);

    1137               0 :         CPLFree(pszTableName);

    1138               0 :         CPLFree(pszSchemaName);

    1139               0 :         CPLFree(pszWhereClause);

    1140               0 :         CPLFree(pszRasterColumnName);

    1141                 : 
    1142               0 :         return NULL;

    1143                 : 
    1144                 :     }
    1145                 : 
    1146                 :     /********************************************
    1147                 :      *  Check if the table has an index
    1148                 :      *  Useful for spatial queries in raster band
    1149                 :      ********************************************/
    1150                 :     bTableHasIndex = 
    1151               0 :         TableHasGISTIndex(hPGconn, pszTableName, pszSchemaName);

    1152                 : 
    1153                 : 
    1154                 :     /*********************************************************************
    1155                 :      * At this point, we can start working with the given database and
    1156                 :      * table. 
    1157                 :      *********************************************************************/
    1158                 : 
    1159                 :     /********************************************************
    1160                 :      *  Instantiate a new Dataset object
    1161                 :      ********************************************************/
    1162               0 :     poDS = new WKTRasterDataset();

    1163                 : 
    1164                 :     /**
    1165                 :      * TODO: Allow regular and irregular blocking. By default,
    1166                 :      * we only allow regular blocking
    1167                 :      */
    1168               0 :     poDS->bTableHasRegularBlocking = TRUE;

    1169                 : 
    1170                 : 
    1171               0 :     poDS->pszRasterColumnName = pszRasterColumnName;

    1172               0 :     poDS->bTableHasGISTIndex = bTableHasIndex;

    1173               0 :     poDS->pszTableName = pszTableName;

    1174               0 :     poDS->pszSchemaName = pszSchemaName;

    1175               0 :     poDS->pszWhereClause = pszWhereClause;

    1176               0 :     poDS->eAccess = poOpenInfo->eAccess;

    1177               0 :     poDS->hPGconn = hPGconn;

    1178               0 :     poDS->bCloseConnection = TRUE;  // dataset must close connection

    1179                 : 
    1180                 : 
    1181                 :     /********************************************
    1182                 :      *  Populate georeference related fields
    1183                 :      ********************************************/
    1184               0 :     if (poDS->SetRasterProperties() == CE_Failure) {

    1185                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1186               0 :             "Couldn't get raster properties.");

    1187               0 :         delete poDS;

    1188               0 :         return NULL;

    1189                 :     } 
    1190                 : 
    1191                 :     /****************************************************************
    1192                 :      * Now, we're going to create the raster bands. First, we need
    1193                 :      * the pixel_types and nodata string representations (PQ arrays)
    1194                 :      ****************************************************************/    
    1195                 :     osCommand.Printf(
    1196                 :             "select pixel_types, nodata_values from raster_columns \
    1197                 :             where r_table_schema = '%s' and r_table_name = '%s' and \
    1198                 :             r_column = '%s'",
    1199                 :             poDS->pszSchemaName, poDS->pszTableName, 
    1200               0 :             poDS->pszRasterColumnName);

    1201               0 :     hPGresult = PQexec(poDS->hPGconn, osCommand.c_str());

    1202               0 :     if (hPGresult == NULL || PQresultStatus(hPGresult) != PGRES_TUPLES_OK 

    1203                 :             || PQntuples(hPGresult) <= 0) 
    1204                 :     {
    1205                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1206               0 :                 "Couldn't get raster properties.");

    1207               0 :         delete poDS;

    1208               0 :         return NULL;

    1209                 :     } 
    1210                 :     else 
    1211                 :     {
    1212               0 :         pszArrayPixelTypes = CPLStrdup(PQgetvalue(hPGresult, 0, 0));

    1213               0 :         pszArrayNodataValues = CPLStrdup(PQgetvalue(hPGresult, 0, 1));

    1214                 : 
    1215                 :         /************************************************************
    1216                 :          * TODO: Use CSLTokenizeString for this
    1217                 :          ************************************************************/
    1218               0 :         int nBands = 1;

    1219                 : 
    1220                 :         // Explode PQ arrays into char **
    1221               0 :         if (pszArrayPixelTypes != NULL)

    1222                 :             papszPixelTypes = poDS->ExplodeArrayString(pszArrayPixelTypes,
    1223               0 :                     &nBands);

    1224               0 :         if (pszArrayNodataValues != NULL) 

    1225                 :         {
    1226                 : 
    1227                 :             /**
    1228                 :              * Has nBands been fetched by the previous call? If yes, 
    1229                 :              * we don't need to fetch it in the next call
    1230                 :              */
    1231               0 :             if (nBands != 0)

    1232                 :                 papszNodataValues =
    1233                 :                         poDS->ExplodeArrayString(pszArrayNodataValues,
    1234               0 :                     &nCountNoDataValues);

    1235                 : 
    1236                 :             // We don't have a value for nBands, try to fetch one
    1237                 :             else
    1238                 :                 papszNodataValues =
    1239                 :                         poDS->ExplodeArrayString(pszArrayNodataValues,
    1240               0 :                     &nBands);

    1241                 :         }
    1242                 : 
    1243               0 :         poDS->nBands = nBands;

    1244                 :     }
    1245                 : 
    1246                 :     
    1247                 :     /**************************************************************
    1248                 :      * Create the raster bands
    1249                 :      **************************************************************/
    1250               0 :     GBool bSignedByte = FALSE;

    1251               0 :     int nBitDepth = 8;

    1252               0 :     for (int iBand = 0; iBand < poDS->nBands; iBand++) 

    1253                 :     {
    1254               0 :         if (pszArrayPixelTypes != NULL && papszPixelTypes != NULL) 

    1255                 :         {
    1256               0 :             if (EQUALN(papszPixelTypes[iBand], "1BB", 3 * sizeof (char))) 

    1257                 :             {
    1258               0 :                 hDataType = GDT_Byte;

    1259               0 :                 nBitDepth = 1;

    1260                 :             }
    1261                 :             
    1262               0 :             else if(EQUALN(papszPixelTypes[iBand], "2BUI", 

    1263                 :                         4 * sizeof (char))) 
    1264                 :             {
    1265               0 :                 hDataType = GDT_Byte;

    1266               0 :                 nBitDepth = 2;

    1267                 :             }
    1268                 : 
    1269               0 :             else if (EQUALN(papszPixelTypes[iBand], "4BUI",

    1270                 :                     4 * sizeof (char))) 
    1271                 :             {
    1272               0 :                 hDataType = GDT_Byte;

    1273               0 :                 nBitDepth = 4;

    1274                 :             }
    1275                 :             
    1276               0 :             else if (EQUALN(papszPixelTypes[iBand], "8BUI",

    1277                 :                     4 * sizeof (char))) 
    1278                 :             {
    1279               0 :                 hDataType = GDT_Byte;

    1280               0 :                 nBitDepth = 8;

    1281                 :             }
    1282                 : 
    1283               0 :             else if (EQUALN(papszPixelTypes[iBand], "8BSI",

    1284                 :                     4 * sizeof (char))) 
    1285                 :             {
    1286               0 :                 hDataType = GDT_Byte;

    1287                 : 
    1288                 :                 /**
    1289                 :                  * To indicate the unsigned byte values between 128 and 255
    1290                 :                  * should be interpreted as being values between -128 and 
    1291                 :                  * -1 for applications that recognise the SIGNEDBYTE type.
    1292                 :                  */
    1293               0 :                 bSignedByte = TRUE;

    1294                 : 
    1295               0 :                 nBitDepth = 8;

    1296                 :             }
    1297                 : 
    1298               0 :             else if (EQUALN(papszPixelTypes[iBand], "16BSI",

    1299                 :                     5 * sizeof (char))) 
    1300                 :             {                
    1301               0 :                 hDataType = GDT_Int16;

    1302               0 :                 nBitDepth = 16;

    1303                 :             }
    1304                 : 
    1305               0 :             else if (EQUALN(papszPixelTypes[iBand], "16BUI",

    1306                 :                     5 * sizeof (char))) 
    1307                 :             {
    1308               0 :                 hDataType = GDT_UInt16;

    1309               0 :                 nBitDepth = 16;

    1310                 :             }
    1311                 : 
    1312               0 :             else if (EQUALN(papszPixelTypes[iBand], "32BSI",

    1313                 :                     5 * sizeof (char))) 
    1314                 :             {
    1315               0 :                 hDataType = GDT_Int32;

    1316               0 :                 nBitDepth = 32;

    1317                 :             }
    1318                 : 
    1319               0 :             else if (EQUALN(papszPixelTypes[iBand], "32BUI",

    1320                 :                     5 * sizeof (char))) 
    1321                 :             {
    1322               0 :                 hDataType = GDT_UInt32;

    1323               0 :                 nBitDepth = 32;

    1324                 :             }
    1325                 : 
    1326                 :                 
    1327               0 :             else if (EQUALN(papszPixelTypes[iBand], "32BF",

    1328                 :                     4 * sizeof (char))) 
    1329                 :             {
    1330               0 :                 hDataType = GDT_Float32;

    1331               0 :                 nBitDepth = 32;

    1332                 :             }
    1333                 : 
    1334               0 :             else if (EQUALN(papszPixelTypes[iBand], "64BF",

    1335                 :                     4 * sizeof (char))) 
    1336                 :             {
    1337               0 :                 hDataType = GDT_Float64;

    1338               0 :                 nBitDepth = 64;

    1339                 :             }
    1340                 : 
    1341                 :             else 
    1342                 :             {
    1343               0 :                 hDataType = GDT_Byte;

    1344               0 :                 nBitDepth = 8;

    1345                 :             }
    1346                 : 
    1347                 :         }
    1348                 : 
    1349                 :         // array of data types doesn't exist or is an empty string
    1350                 :         else 
    1351                 :         {
    1352               0 :             hDataType = GDT_Byte;

    1353               0 :             nBitDepth = 8;

    1354                 :         }
    1355                 : 
    1356               0 :         if (pszArrayNodataValues != NULL && papszNodataValues != NULL &&

    1357                 :             iBand < nCountNoDataValues) 
    1358                 :         {
    1359               0 :             dfNoDataValue = atof(papszNodataValues[iBand]);        

    1360                 :         }
    1361                 : 
    1362                 :         // array of nodata values doesn't exist or is an empty string
    1363                 :         else 
    1364                 :         {
    1365               0 :             dfNoDataValue = 0.0;

    1366                 :         }
    1367                 : 
    1368                 : 
    1369                 :         // Create raster band objects
    1370                 :         poDS->SetBand(iBand + 1, new WKTRasterRasterBand(poDS, iBand + 1,
    1371               0 :                 hDataType, dfNoDataValue, bSignedByte, nBitDepth));

    1372                 :     }
    1373                 : 
    1374                 : 
    1375                 :     /******************************************************
    1376                 :      * Create overviews datasets, if does exist
    1377                 :      ******************************************************/
    1378               0 :     bExistsOverviewsTable = ExistsOverviewsTable(hPGconn);

    1379               0 :     if (bExistsOverviewsTable) 

    1380                 :     {
    1381                 :         // Count the number of overviews        
    1382                 :         osCommand.Printf(
    1383                 :                 "select o_table_name, overview_factor, o_column, \
    1384                 :                 o_table_schema from raster_overviews where \
    1385                 :                 r_table_schema = '%s' and r_table_name = '%s'",
    1386               0 :                 poDS->pszSchemaName, poDS->pszTableName);

    1387               0 :         hPGresult = PQexec(poDS->hPGconn, osCommand.c_str());

    1388                 : 
    1389                 :         // no overviews
    1390               0 :         if (

    1391                 :                 hPGresult == NULL ||
    1392                 :                 PQresultStatus(hPGresult) != PGRES_TUPLES_OK ||
    1393                 :                 PQntuples(hPGresult) <= 0
    1394                 :                 ) 
    1395                 :         {
    1396               0 :             poDS->nOverviews = 0;

    1397                 :         }
    1398                 :             // overviews
    1399                 :         else 
    1400                 :         {
    1401               0 :             poDS->nOverviews = PQntuples(hPGresult);

    1402                 :         }
    1403                 : 
    1404                 : 
    1405                 :         /**
    1406                 :          * Create overviews's Datasets and metadata
    1407                 :          */
    1408               0 :         if (poDS->nOverviews > 0) 

    1409                 :         {
    1410                 : 
    1411                 :             poDS->papoWKTRasterOv =
    1412                 :                     (WKTRasterDataset **) VSICalloc(poDS->nOverviews,
    1413               0 :                     sizeof (WKTRasterDataset *));

    1414               0 :             if (poDS->papoWKTRasterOv == NULL) 

    1415                 :             {
    1416                 :                 CPLError(CE_Warning, CPLE_ObjectNull,
    1417               0 :                         "Couldn't allocate memory for overviews. Number \

    1418                 :                         of overviews will be set to 0");
    1419               0 :                 poDS->nOverviews = 0;

    1420                 :             }
    1421                 :             else 
    1422                 :             {
    1423                 : 
    1424               0 :                 for (int i = 0; i < poDS->nOverviews; i++) 

    1425                 :                 {
    1426                 :                     /**
    1427                 :                      * CREATE DATASETS
    1428                 :                      */
    1429                 : 
    1430                 :                     // AND RASTERXSIZE?? IT SHOULD BE REDUCED...
    1431               0 :                     poDS->papoWKTRasterOv[i] = new WKTRasterDataset();

    1432                 :                     poDS->papoWKTRasterOv[i]->nBlockSizeX =
    1433               0 :                             poDS->nBlockSizeX;

    1434                 :                     poDS->papoWKTRasterOv[i]->nBlockSizeY =
    1435               0 :                             poDS->nBlockSizeY;

    1436                 : 
    1437                 :                     int nOverviewFactor = atoi(
    1438               0 :                             PQgetvalue(hPGresult, i, 1));

    1439                 :                     char * pszOVTableName = CPLStrdup(
    1440               0 :                             PQgetvalue(hPGresult, i, 0));

    1441                 :                     char * pszOVColumnName = CPLStrdup(
    1442               0 :                             PQgetvalue(hPGresult, i, 2));

    1443                 :                     char * pszOVSchemaName = CPLStrdup(
    1444               0 :                             PQgetvalue(hPGresult, i, 3));

    1445                 : 
    1446                 :                     /**
    1447                 :                      * m/px is bigger in ov, because we are more far...
    1448                 :                      */
    1449                 :                     poDS->papoWKTRasterOv[i]->dfPixelSizeX =
    1450               0 :                             poDS->dfPixelSizeX * nOverviewFactor;

    1451                 : 
    1452                 :                     poDS->papoWKTRasterOv[i]->dfPixelSizeY =
    1453               0 :                             poDS->dfPixelSizeY * nOverviewFactor;

    1454                 : 
    1455                 :                     /**
    1456                 :                      * But raster size is smaller, for the same reason
    1457                 :                      * (we're more far covering the same area)
    1458                 :                      */
    1459                 :                     poDS->papoWKTRasterOv[i]->nRasterXSize =
    1460               0 :                             poDS->nRasterXSize / nOverviewFactor;

    1461                 : 
    1462                 :                     poDS->papoWKTRasterOv[i]->nRasterYSize =
    1463               0 :                             poDS->nRasterYSize / nOverviewFactor;

    1464                 : 
    1465                 :                     // Check these values (are correct??)
    1466               0 :                     poDS->papoWKTRasterOv[i]->dfSkewX = poDS->dfSkewX;

    1467               0 :                     poDS->papoWKTRasterOv[i]->dfSkewY = poDS->dfSkewY;

    1468                 :                     poDS->papoWKTRasterOv[i]->dfUpperLeftX =
    1469               0 :                         poDS->dfUpperLeftX;

    1470                 :                     poDS->papoWKTRasterOv[i]->dfUpperLeftY = 
    1471               0 :                         poDS->dfUpperLeftY;

    1472                 : 
    1473               0 :                     poDS->papoWKTRasterOv[i]->hPGconn = poDS->hPGconn;

    1474                 :                     
    1475                 :                     // children datasets don't close connection
    1476               0 :                     poDS->papoWKTRasterOv[i]->bCloseConnection = FALSE;

    1477                 :                     poDS->papoWKTRasterOv[i]->pszTableName = 
    1478               0 :                         pszOVTableName;

    1479                 :                     poDS->papoWKTRasterOv[i]->pszSchemaName = 
    1480               0 :                         pszOVSchemaName;

    1481                 :                     poDS->papoWKTRasterOv[i]->pszRasterColumnName =
    1482               0 :                             pszOVColumnName;

    1483                 : 
    1484                 :                     poDS->papoWKTRasterOv[i]->pszWhereClause =
    1485                 :                             (poDS->pszWhereClause != NULL) ?
    1486                 :                                 CPLStrdup(poDS->pszWhereClause):
    1487               0 :                                 NULL;

    1488                 : 
    1489                 :                     GBool bOVTableHasIndex = 
    1490                 :                         TableHasGISTIndex(poDS->hPGconn, pszOVTableName, 
    1491               0 :                                 pszOVSchemaName);

    1492                 :                     poDS->papoWKTRasterOv[i]->bTableHasGISTIndex =
    1493               0 :                             bOVTableHasIndex;

    1494                 : 
    1495               0 :                     poDS->papoWKTRasterOv[i]->nSrid = poDS->nSrid;

    1496                 : 
    1497                 : 
    1498                 :                     /**
    1499                 :                      * CREATE OVERVIEWS RASTER BANDS
    1500                 :                      */
    1501               0 :                     poDS->papoWKTRasterOv[i]->nBands = poDS->nBands;

    1502               0 :                     for (int j = 0; j < poDS->nBands; j++) 

    1503                 :                     {
    1504                 :                         WKTRasterRasterBand * poWKTRB =
    1505                 :                                 (WKTRasterRasterBand *)
    1506               0 :                                 (poDS->GetRasterBand(j + 1));

    1507                 : 
    1508                 :                         poDS->papoWKTRasterOv[i]->SetBand(j + 1,
    1509                 :                                 new WKTRasterRasterBand(
    1510                 :                                 poDS->papoWKTRasterOv[i],
    1511                 :                                 j + 1, poWKTRB->GetRasterDataType(),
    1512                 :                                 poWKTRB->GetNoDataValue(),
    1513                 :                                 poWKTRB->IsSignedByteDataType(),
    1514               0 :                                 poWKTRB->GetNBitDepth()));

    1515                 :                     }
    1516                 :                    
    1517                 :                 } // end of creating overviews
    1518                 : 
    1519                 :             } // end else
    1520                 : 
    1521                 :             // free result
    1522               0 :             PQclear(hPGresult);

    1523                 : 
    1524                 :         } // end if nOverviews > 0
    1525                 :     } // end if exists overview table
    1526                 : 
    1527                 :     /****************** Overviews created **********************/
    1528                 : 
    1529                 :     
    1530                 :     /***********************************************************
    1531                 :      * Free memory
    1532                 :      ***********************************************************/
    1533               0 :     CSLDestroy(papszPixelTypes);

    1534               0 :     CSLDestroy(papszNodataValues);

    1535               0 :     CPLFree(pszArrayPixelTypes);

    1536               0 :     CPLFree(pszArrayNodataValues);

    1537                 : 
    1538                 :      // All WKT Raster bands are consecutives
    1539               0 :     poDS->SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE");

    1540                 : 
    1541               0 :     return poDS;

    1542                 : }
    1543                 : 
    1544                 : /**
    1545                 :  * Method: GetGeoTransform
    1546                 :  * Fetches the coefficients for transforming between pixel/line (P,L) 
    1547                 :  * raster space and projection coordinates (Xp, Yp) space
    1548                 :  * The affine transformation performed is:
    1549                 :  *  Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
    1550                 :  *  Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
    1551                 :  * Parameters:
    1552                 :  *  - double *: pointer to a double array, that will contains the affine
    1553                 :  *  transformation matrix coefficients
    1554                 :  * Returns:
    1555                 :  *  - CPLErr: CE_None on success, or CE_Failure if no transform can be 
    1556                 :  *            fetched.
    1557                 :  */
    1558               0 : CPLErr WKTRasterDataset::GetGeoTransform(double * padfTransform) {

    1559                 :     // checking input parameters
    1560                 :     // NOT NEEDED (Is illegal to call GetGeoTransform with a NULL
    1561                 :     // argument. Thanks to Even Rouault)
    1562                 :     /*
    1563                 :     if (padfTransform == NULL)
    1564                 :     {
    1565                 :             // default matrix
    1566                 :             padfTransform[0] = 0.0;
    1567                 :             padfTransform[1] = 1.0;
    1568                 :             padfTransform[2] = 0.0;
    1569                 :             padfTransform[3] = 0.0;
    1570                 :             padfTransform[4] = 0.0;
    1571                 :             padfTransform[5] = 1.0;
    1572                 : 
    1573                 :             return CE_Failure;
    1574                 :     }
    1575                 :      */
    1576                 : 
    1577                 :     // copy necessary values in supplied buffer
    1578               0 :     padfTransform[0] = dfUpperLeftX;

    1579               0 :     padfTransform[1] = dfPixelSizeX;

    1580               0 :     padfTransform[2] = dfSkewX;

    1581               0 :     padfTransform[3] = dfUpperLeftY;

    1582               0 :     padfTransform[4] = dfSkewY;

    1583               0 :     padfTransform[5] = dfPixelSizeY;

    1584                 :         
    1585               0 :     return CE_None;

    1586                 : 
    1587                 :     
    1588                 : }
    1589                 : 
    1590                 : /**
    1591                 :  * Fetch the projection definition string for this dataset in OpenGIS WKT
    1592                 :  * format. It should be suitable for use with the OGRSpatialReference class
    1593                 :  * Parameters: none
    1594                 :  * Returns:
    1595                 :  *  - const char *: a pointer to an internal projection reference string.
    1596                 :  *                  It should not be altered, freed or expected to last for
    1597                 :  *                  long.
    1598                 :  */
    1599               0 : const char * WKTRasterDataset::GetProjectionRef() {

    1600               0 :     CPLString osCommand;

    1601                 :     PGresult * hResult;
    1602                 :     char * pszProjection;
    1603                 : 
    1604               0 :     if (nSrid == -1) {

    1605               0 :         return "";

    1606                 :     }
    1607                 : 
    1608                 :     /********************************************************
    1609                 :      *        Reading proj from database
    1610                 :      ********************************************************/    
    1611                 :     osCommand.Printf("SELECT srtext FROM spatial_ref_sys where SRID=%d", 
    1612               0 :             nSrid);

    1613                 : 
    1614               0 :     hResult = PQexec(this->hPGconn, osCommand.c_str());

    1615                 : 
    1616               0 :     if (hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK

    1617                 :             && PQntuples(hResult) > 0) 
    1618                 :     {
    1619               0 :         pszProjection = CPLStrdup(PQgetvalue(hResult, 0, 0));

    1620                 :     }
    1621                 : 
    1622               0 :     if (hResult)

    1623               0 :         PQclear(hResult);

    1624                 : 
    1625               0 :     return pszProjection;

    1626                 : }
    1627                 : 
    1628                 : /**
    1629                 :  * Set the projection reference string for this dataset. The string should
    1630                 :  * be in OGC WKT or PROJ.4 format
    1631                 :  * Parameters:
    1632                 :  *  - const char *: projection reference string.
    1633                 :  * Returns:
    1634                 :  *  - CE_Failure if an error occurs, otherwise CE_None.
    1635                 :  */
    1636               0 : CPLErr WKTRasterDataset::SetProjection(const char * pszProjectionRef)

    1637                 : {
    1638               0 :     VALIDATE_POINTER1(pszProjectionRef, "SetProjection", CE_Failure);

    1639                 : 
    1640               0 :     CPLString osCommand;

    1641                 :     PGresult * hResult;
    1642               0 :     int nFetchedSrid = -1;

    1643                 : 
    1644                 : 
    1645                 :     /*****************************************************************
    1646                 :      * Check if the dataset allows updating
    1647                 :      *****************************************************************/
    1648               0 :     if (GetAccess() != GA_Update) {

    1649                 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    1650               0 :                 "This driver doesn't allow write access");

    1651               0 :         return CE_Failure;

    1652                 :     }
    1653                 : 
    1654                 :     /*****************************************************************
    1655                 :      * Look for projection with this text
    1656                 :      *****************************************************************/
    1657                 : 
    1658                 :     // First, WKT text
    1659                 :     osCommand.Printf("SELECT srid FROM spatial_ref_sys where srtext='%s'",
    1660               0 :             pszProjectionRef);

    1661               0 :     hResult = PQexec(hPGconn, osCommand.c_str());

    1662                 : 
    1663               0 :     if (hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK

    1664                 :             && PQntuples(hResult) > 0) 
    1665                 :     {
    1666                 : 
    1667               0 :         nFetchedSrid = atoi(PQgetvalue(hResult, 0, 0));

    1668                 : 
    1669                 :         // update class attribute
    1670               0 :         nSrid = nFetchedSrid;

    1671                 : 
    1672                 : 
    1673                 :         // update raster_columns table
    1674                 :         osCommand.Printf("UPDATE raster_columns SET srid=%d WHERE \
    1675                 :                     r_table_name = '%s' AND r_column = '%s'",
    1676               0 :                 nSrid, pszTableName, pszRasterColumnName);

    1677               0 :         hResult = PQexec(hPGconn, osCommand.c_str());

    1678               0 :         if (hResult == NULL || PQresultStatus(hResult) != PGRES_COMMAND_OK)

    1679                 :         {
    1680                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1681                 :                     "Couldn't update raster_columns table: %s",
    1682               0 :                     PQerrorMessage(hPGconn));

    1683               0 :             return CE_Failure;

    1684                 :         }
    1685                 : 
    1686                 :         // TODO: Update ALL blocks with the new srid...
    1687                 : 
    1688               0 :         return CE_None;

    1689                 :     }
    1690                 : 
    1691                 :     // If not, proj4 text
    1692                 :     else 
    1693                 :     {
    1694                 :         osCommand.Printf(
    1695                 :                 "SELECT srid FROM spatial_ref_sys where proj4text='%s'",
    1696               0 :             pszProjectionRef);

    1697               0 :         hResult = PQexec(this->hPGconn, osCommand.c_str());

    1698                 : 
    1699               0 :         if (hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK

    1700                 :             && PQntuples(hResult) > 0) 
    1701                 :         {
    1702                 : 
    1703               0 :             nFetchedSrid = atoi(PQgetvalue(hResult, 0, 0));

    1704                 : 
    1705                 :             // update class attribute
    1706               0 :             nSrid = nFetchedSrid;

    1707                 : 
    1708                 :             // update raster_columns table            
    1709                 :             osCommand.Printf("UPDATE raster_columns SET srid=%d WHERE \
    1710                 :                     r_table_name = '%s' AND r_column = '%s'",
    1711               0 :                     nSrid, pszTableName, pszRasterColumnName);

    1712                 : 
    1713               0 :             hResult = PQexec(hPGconn, osCommand.c_str());

    1714               0 :             if (hResult == NULL ||

    1715                 :                     PQresultStatus(hResult) != PGRES_COMMAND_OK) 
    1716                 :             {
    1717                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1718                 :                         "Couldn't update raster_columns table: %s",
    1719               0 :                         PQerrorMessage(hPGconn));

    1720               0 :                 return CE_Failure;

    1721                 :             }
    1722                 : 
    1723                 :             // TODO: Update ALL blocks with the new srid...
    1724                 : 
    1725               0 :             return CE_None;

    1726                 :         }
    1727                 : 
    1728                 :         else 
    1729                 :         {
    1730                 :             CPLError(CE_Failure, CPLE_WrongFormat,
    1731               0 :                     "Couldn't find WKT neither proj4 definition");

    1732               0 :             return CE_Failure;

    1733                 :         }
    1734               0 :     }

    1735                 : }
    1736                 : 
    1737                 : /**
    1738                 :  * Set the affine transformation coefficients.
    1739                 :  * Parameters:
    1740                 :  *  - double *:a six double buffer containing the transformation
    1741                 :  *             coefficients to be written with the dataset.
    1742                 :  *  Returns:
    1743                 :  *  - CE_None on success, or CE_Failure if this transform cannot be written.
    1744                 :  */
    1745               0 : CPLErr WKTRasterDataset::SetGeoTransform(double * padfTransform)

    1746                 : {
    1747               0 :     VALIDATE_POINTER1(padfTransform, "SetGeoTransform", CE_Failure);

    1748                 : 
    1749               0 :     dfUpperLeftX = padfTransform[0];

    1750               0 :     dfPixelSizeX = padfTransform[1];

    1751               0 :     dfSkewX = padfTransform[2];

    1752               0 :     dfUpperLeftY = padfTransform[3];

    1753               0 :     dfSkewY = padfTransform[4];

    1754               0 :     dfPixelSizeY = padfTransform[5];

    1755                 : 
    1756                 :     // TODO: Update all data blocks with these values
    1757                 :     
    1758               0 :     return CE_None;

    1759                 : }
    1760                 : 
    1761                 : 
    1762                 : /************************************************************************/
    1763                 : /*                          GDALRegister_WKTRaster()                    */
    1764                 : /************************************************************************/
    1765             409 : void GDALRegister_WKTRaster() 

    1766                 : {
    1767                 :     GDALDriver *poDriver;
    1768                 : 
    1769             409 :     if (GDALGetDriverByName("WKTRaster") == NULL) {

    1770             392 :         poDriver = new GDALDriver();

    1771                 : 
    1772             392 :         poDriver->SetDescription("WKTRaster");

    1773                 :         poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
    1774             392 :                 "PostGIS WKT Raster driver");

    1775                 : 
    1776             392 :         poDriver->pfnOpen = WKTRasterDataset::Open;

    1777                 : 
    1778             392 :         GetGDALDriverManager()->RegisterDriver(poDriver);

    1779                 :     }
    1780             409 : }

    1781                 : 

Generated by: LTP GCOV extension version 1.5