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