1 /******************************************************************************
2  * $Id: ogrpgeolayer.cpp 28375 2015-01-30 12:06:11Z rouault $
3  *
4  * Project:  OpenGIS Simple Features Reference Implementation
5  * Purpose:  Implements OGRPGeoLayer class, code shared between
6  *           the direct table access, and the generic SQL results.
7  * Author:   Frank Warmerdam, warmerdam@pobox.com
8  *
9  ******************************************************************************
10  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
11  * Copyright (c) 2008-2014, Even Rouault <even dot rouault at mines-paris dot org>
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a
14  * copy of this software and associated documentation files (the "Software"),
15  * to deal in the Software without restriction, including without limitation
16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  * and/or sell copies of the Software, and to permit persons to whom the
18  * Software is furnished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included
21  * in all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29  * DEALINGS IN THE SOFTWARE.
30  ****************************************************************************/
31 
32 #include "cpl_conv.h"
33 #include "ogr_pgeo.h"
34 #include "cpl_string.h"
35 #include "ogrpgeogeometry.h"
36 
37 CPL_CVSID("$Id: ogrpgeolayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
38 
39 /************************************************************************/
40 /*                            OGRPGeoLayer()                            */
41 /************************************************************************/
42 
OGRPGeoLayer()43 OGRPGeoLayer::OGRPGeoLayer()
44 
45 {
46     poDS = NULL;
47 
48     pszGeomColumn = NULL;
49     pszFIDColumn = NULL;
50 
51     poStmt = NULL;
52 
53     iNextShapeId = 0;
54 
55     poSRS = NULL;
56     nSRSId = -2; // we haven't even queried the database for it yet.
57 }
58 
59 /************************************************************************/
60 /*                            ~OGRPGeoLayer()                             */
61 /************************************************************************/
62 
~OGRPGeoLayer()63 OGRPGeoLayer::~OGRPGeoLayer()
64 
65 {
66     if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
67     {
68         CPLDebug( "PGeo", "%d features read on layer '%s'.",
69                   (int) m_nFeaturesRead,
70                   poFeatureDefn->GetName() );
71     }
72 
73     if( poStmt != NULL )
74     {
75         delete poStmt;
76         poStmt = NULL;
77     }
78 
79     if( poFeatureDefn != NULL )
80     {
81         poFeatureDefn->Release();
82         poFeatureDefn = NULL;
83     }
84 
85     CPLFree( pszGeomColumn );
86     CPLFree( panFieldOrdinals );
87     CPLFree( pszFIDColumn );
88 
89     if( poSRS != NULL )
90     {
91         poSRS->Release();
92         poSRS = NULL;
93     }
94 }
95 
96 /************************************************************************/
97 /*                          BuildFeatureDefn()                          */
98 /*                                                                      */
99 /*      Build feature definition from a set of column definitions       */
100 /*      set on a statement.  Sift out geometry and FID fields.          */
101 /************************************************************************/
102 
BuildFeatureDefn(const char * pszLayerName,CPLODBCStatement * poStmt)103 CPLErr OGRPGeoLayer::BuildFeatureDefn( const char *pszLayerName,
104                                        CPLODBCStatement *poStmt )
105 
106 {
107     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
108     SetDescription( poFeatureDefn->GetName() );
109     int    nRawColumns = poStmt->GetColCount();
110 
111     poFeatureDefn->Reference();
112     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
113 
114     panFieldOrdinals = (int *) CPLMalloc( sizeof(int) * nRawColumns );
115 
116     for( int iCol = 0; iCol < nRawColumns; iCol++ )
117     {
118         OGRFieldDefn    oField( poStmt->GetColName(iCol), OFTString );
119 
120         oField.SetWidth( MAX(0,poStmt->GetColSize( iCol )) );
121 
122         if( pszGeomColumn != NULL
123             && EQUAL(poStmt->GetColName(iCol),pszGeomColumn) )
124             continue;
125 
126         if( pszFIDColumn == NULL
127             && EQUAL(poStmt->GetColName(iCol),"OBJECTID") )
128         {
129             pszFIDColumn = CPLStrdup(poStmt->GetColName(iCol));
130         }
131 
132         if( pszGeomColumn == NULL
133             && EQUAL(poStmt->GetColName(iCol),"Shape") )
134         {
135             pszGeomColumn = CPLStrdup(poStmt->GetColName(iCol));
136             continue;
137         }
138 
139         switch( poStmt->GetColType(iCol) )
140         {
141           case SQL_INTEGER:
142           case SQL_SMALLINT:
143             oField.SetType( OFTInteger );
144             break;
145 
146           case SQL_BINARY:
147           case SQL_VARBINARY:
148           case SQL_LONGVARBINARY:
149             oField.SetType( OFTBinary );
150             break;
151 
152           case SQL_DECIMAL:
153             oField.SetType( OFTReal );
154             oField.SetPrecision( poStmt->GetColPrecision(iCol) );
155             break;
156 
157           case SQL_FLOAT:
158           case SQL_REAL:
159           case SQL_DOUBLE:
160             oField.SetType( OFTReal );
161             oField.SetWidth( 0 );
162             break;
163 
164           case SQL_C_DATE:
165             oField.SetType( OFTDate );
166             break;
167 
168           case SQL_C_TIME:
169             oField.SetType( OFTTime );
170             break;
171 
172           case SQL_C_TIMESTAMP:
173             oField.SetType( OFTDateTime );
174             break;
175 
176           default:
177             /* leave it as OFTString */;
178         }
179 
180         if( pszGeomColumn != NULL )
181             poFeatureDefn->GetGeomFieldDefn(0)->SetName(pszGeomColumn);
182 
183         poFeatureDefn->AddFieldDefn( &oField );
184         panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol+1;
185     }
186 
187     return CE_None;
188 }
189 
190 
191 /************************************************************************/
192 /*                            ResetReading()                            */
193 /************************************************************************/
194 
ResetReading()195 void OGRPGeoLayer::ResetReading()
196 
197 {
198     iNextShapeId = 0;
199 }
200 
201 /************************************************************************/
202 /*                           GetNextFeature()                           */
203 /************************************************************************/
204 
GetNextFeature()205 OGRFeature *OGRPGeoLayer::GetNextFeature()
206 
207 {
208     for( ; TRUE; )
209     {
210         OGRFeature      *poFeature;
211 
212         poFeature = GetNextRawFeature();
213         if( poFeature == NULL )
214             return NULL;
215 
216         if( (m_poFilterGeom == NULL
217             || FilterGeometry( poFeature->GetGeometryRef() ) )
218             && (m_poAttrQuery == NULL
219                 || m_poAttrQuery->Evaluate( poFeature )) )
220             return poFeature;
221 
222         delete poFeature;
223     }
224 }
225 
226 /************************************************************************/
227 /*                         GetNextRawFeature()                          */
228 /************************************************************************/
229 
GetNextRawFeature()230 OGRFeature *OGRPGeoLayer::GetNextRawFeature()
231 
232 {
233     OGRErr err = OGRERR_NONE;
234 
235     if( GetStatement() == NULL )
236         return NULL;
237 
238 /* -------------------------------------------------------------------- */
239 /*      If we are marked to restart then do so, and fetch a record.     */
240 /* -------------------------------------------------------------------- */
241     if( !poStmt->Fetch() )
242     {
243         delete poStmt;
244         poStmt = NULL;
245         return NULL;
246     }
247 
248 /* -------------------------------------------------------------------- */
249 /*      Create a feature from the current result.                       */
250 /* -------------------------------------------------------------------- */
251     int         iField;
252     OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
253 
254     if( pszFIDColumn != NULL && poStmt->GetColId(pszFIDColumn) > -1 )
255         poFeature->SetFID(
256             atoi(poStmt->GetColData(poStmt->GetColId(pszFIDColumn))) );
257     else
258         poFeature->SetFID( iNextShapeId );
259 
260     iNextShapeId++;
261     m_nFeaturesRead++;
262 
263 /* -------------------------------------------------------------------- */
264 /*      Set the fields.                                                 */
265 /* -------------------------------------------------------------------- */
266     for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
267     {
268         int iSrcField = panFieldOrdinals[iField]-1;
269         const char *pszValue = poStmt->GetColData( iSrcField );
270 
271         if( pszValue == NULL )
272             /* no value */;
273         else if( poFeature->GetFieldDefnRef(iField)->GetType() == OFTBinary )
274             poFeature->SetField( iField,
275                                  poStmt->GetColDataLength(iSrcField),
276                                  (GByte *) pszValue );
277         else
278             poFeature->SetField( iField, pszValue );
279     }
280 
281 /* -------------------------------------------------------------------- */
282 /*      Try to extract a geometry.                                      */
283 /* -------------------------------------------------------------------- */
284     if( pszGeomColumn != NULL )
285     {
286         int iField = poStmt->GetColId( pszGeomColumn );
287         GByte *pabyShape = (GByte *) poStmt->GetColData( iField );
288         int nBytes = poStmt->GetColDataLength(iField);
289         OGRGeometry *poGeom = NULL;
290 
291         if( pabyShape != NULL )
292         {
293             err = OGRCreateFromShapeBin( pabyShape, &poGeom, nBytes );
294             if( OGRERR_NONE != err )
295             {
296                 CPLDebug( "PGeo",
297                           "Translation shape binary to OGR geometry failed (FID=%ld)",
298                            (long)poFeature->GetFID() );
299             }
300         }
301 
302         if( poGeom != NULL && OGRERR_NONE == err )
303         {
304             poGeom->assignSpatialReference( poSRS );
305             poFeature->SetGeometryDirectly( poGeom );
306         }
307     }
308 
309     return poFeature;
310 }
311 
312 /************************************************************************/
313 /*                             GetFeature()                             */
314 /************************************************************************/
315 
GetFeature(GIntBig nFeatureId)316 OGRFeature *OGRPGeoLayer::GetFeature( GIntBig nFeatureId )
317 
318 {
319     /* This should be implemented directly! */
320 
321     return OGRLayer::GetFeature( nFeatureId );
322 }
323 
324 /************************************************************************/
325 /*                           TestCapability()                           */
326 /************************************************************************/
327 
TestCapability(CPL_UNUSED const char * pszCap)328 int OGRPGeoLayer::TestCapability( CPL_UNUSED const char * pszCap )
329 {
330     return FALSE;
331 }
332 
333 /************************************************************************/
334 /*                           TestCapability()                           */
335 /************************************************************************/
336 
LookupSRID(int nSRID)337 void OGRPGeoLayer::LookupSRID( int nSRID )
338 
339 {
340 /* -------------------------------------------------------------------- */
341 /*      Fetch the corresponding WKT from the SpatialRef table.          */
342 /* -------------------------------------------------------------------- */
343     CPLODBCStatement oStmt( poDS->GetSession() );
344 
345     oStmt.Appendf( "SELECT srtext FROM GDB_SpatialRefs WHERE srid = %d",
346                   nSRID );
347 
348     if( !oStmt.ExecuteSQL() )
349     {
350         CPLError( CE_Failure, CPLE_AppDefined,
351                   "'%s' failed.\n%s",
352                   oStmt.GetCommand(),
353                   poDS->GetSession()->GetLastError() );
354         return;
355     }
356 
357     if( !oStmt.Fetch() )
358     {
359         CPLError( CE_Warning, CPLE_AppDefined,
360                   "SRID %d lookup failed.\n%s",
361                   nSRID, poDS->GetSession()->GetLastError() );
362         return;
363     }
364 
365 /* -------------------------------------------------------------------- */
366 /*      Check that it isn't just a GUID.  We don't know how to          */
367 /*      translate those.                                                */
368 /* -------------------------------------------------------------------- */
369     char *pszSRText = (char *) oStmt.GetColData(0);
370 
371     if( pszSRText[0] == '{' )
372     {
373         CPLDebug( "PGEO", "Ignoreing GUID SRTEXT: %s", pszSRText );
374         return;
375     }
376 
377 /* -------------------------------------------------------------------- */
378 /*      Turn it into an OGRSpatialReference.                            */
379 /* -------------------------------------------------------------------- */
380     poSRS = new OGRSpatialReference();
381 
382     if( poSRS->importFromWkt( &pszSRText ) != OGRERR_NONE )
383     {
384         CPLError( CE_Failure, CPLE_AppDefined,
385                   "importFromWKT() failed on SRS '%s'.",
386                   pszSRText);
387         delete poSRS;
388         poSRS = NULL;
389     }
390     else if( poSRS->morphFromESRI() != OGRERR_NONE )
391     {
392         CPLError( CE_Failure, CPLE_AppDefined,
393                   "morphFromESRI() failed on SRS." );
394         delete poSRS;
395         poSRS = NULL;
396     }
397     else
398         nSRSId = nSRID;
399 }
400 
401 /************************************************************************/
402 /*                            GetFIDColumn()                            */
403 /************************************************************************/
404 
GetFIDColumn()405 const char *OGRPGeoLayer::GetFIDColumn()
406 
407 {
408     if( pszFIDColumn != NULL )
409         return pszFIDColumn;
410     else
411         return "";
412 }
413 
414 /************************************************************************/
415 /*                         GetGeometryColumn()                          */
416 /************************************************************************/
417 
GetGeometryColumn()418 const char *OGRPGeoLayer::GetGeometryColumn()
419 
420 {
421     if( pszGeomColumn != NULL )
422         return pszGeomColumn;
423     else
424         return "";
425 }
426