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