1 /******************************************************************************
2 * $Id: ogridblayer.cpp 28375 2015-01-30 12:06:11Z rouault $
3 *
4 * Project: OpenGIS Simple Features Reference Implementation
5 * Purpose: Implements OGRIDBLayer class, code shared between
6 * the direct table access, and the generic SQL results
7 * (based on ODBC and PG drivers).
8 * Author: Oleg Semykin, oleg.semykin@gmail.com
9 *
10 ******************************************************************************
11 * Copyright (c) 2006, Oleg Semykin
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_idb.h"
34 #include "cpl_string.h"
35
36 CPL_CVSID("$Id: ogridblayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
37
38 /************************************************************************/
39 /* OGRIDBLayer() */
40 /************************************************************************/
41
OGRIDBLayer()42 OGRIDBLayer::OGRIDBLayer()
43
44 {
45 poDS = NULL;
46
47 bGeomColumnWKB = FALSE;
48 pszFIDColumn = NULL;
49 pszGeomColumn = NULL;
50
51 poCurr = 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 /* ~OGRIDBLayer() */
61 /************************************************************************/
62
~OGRIDBLayer()63 OGRIDBLayer::~OGRIDBLayer()
64
65 {
66 if( poCurr != NULL )
67 {
68 poCurr->Close();
69 delete poCurr;
70 poCurr = NULL;
71 }
72
73 if( pszGeomColumn )
74 CPLFree( pszGeomColumn );
75
76 if(pszFIDColumn)
77 CPLFree( pszFIDColumn );
78
79 if( poFeatureDefn )
80 {
81 poFeatureDefn->Release();
82 poFeatureDefn = NULL;
83 }
84
85 if( poSRS )
86 poSRS->Release();
87 }
88
89 /************************************************************************/
90 /* BuildFeatureDefn() */
91 /* */
92 /* Build feature definition from a set of column definitions */
93 /* set on a statement. Sift out geometry and FID fields. */
94 /************************************************************************/
95
BuildFeatureDefn(const char * pszLayerName,ITCursor * poCurr)96 CPLErr OGRIDBLayer::BuildFeatureDefn( const char *pszLayerName,
97 ITCursor *poCurr )
98
99 {
100 poFeatureDefn = new OGRFeatureDefn( pszLayerName );
101 SetDescription( poFeatureDefn->GetName() );
102 const ITTypeInfo * poInfo = poCurr->RowType();
103 int nRawColumns = poInfo->ColumnCount();
104
105 poFeatureDefn->Reference();
106
107 for( int iCol = 0; iCol < nRawColumns; iCol++ )
108 {
109 const char * pszColName = poInfo->ColumnName(iCol);
110 const ITTypeInfo * poTI = poInfo->ColumnType(iCol);
111 const char * pszTypName = poTI->Name();
112
113 OGRFieldDefn oField( pszColName, OFTString );
114
115 oField.SetWidth( MAX(0,poTI->Bound()) );
116
117 if ( pszGeomColumn != NULL && EQUAL(pszColName,pszGeomColumn) )
118 continue;
119
120 if ( EQUALN("st_", pszTypName, 3) && pszGeomColumn == NULL )
121 {
122 // We found spatial column!
123 pszGeomColumn = CPLStrdup(pszColName);
124
125 if ( EQUAL("st_point", pszTypName) )
126 poFeatureDefn->SetGeomType( wkbPoint );
127 else if ( EQUAL("st_linestring", pszTypName) )
128 poFeatureDefn->SetGeomType( wkbLineString );
129 else if ( EQUAL("st_polygon", pszTypName) )
130 poFeatureDefn->SetGeomType( wkbPolygon );
131 else if ( EQUAL("st_multipoint", pszTypName) )
132 poFeatureDefn->SetGeomType( wkbMultiPoint );
133 else if ( EQUAL("st_multilinestring", pszTypName) )
134 poFeatureDefn->SetGeomType( wkbMultiLineString );
135 else if ( EQUAL("st_multipolygon", pszTypName) )
136 poFeatureDefn->SetGeomType( wkbMultiPolygon );
137
138 continue;
139 }
140
141 // Check other field types
142 if ( EQUAL( pszTypName, "blob" ) ||
143 EQUAL( pszTypName, "byte" ) ||
144 EQUAL( pszTypName, "opaque" ) ||
145 EQUAL( pszTypName, "text" ) ||
146 EQUALN( pszTypName, "list", 4 ) ||
147 EQUALN( pszTypName, "collection", 10 ) ||
148 EQUALN( pszTypName, "row", 3 ) ||
149 EQUALN( pszTypName, "set", 3 ) )
150 {
151 CPLDebug( "OGR_IDB", "'%s' column type not supported yet. Column '%s'",
152 pszTypName, pszColName );
153 continue;
154 }
155
156 if ( EQUALN( pszTypName, "st_", 3 ) )
157 {
158 oField.SetType( OFTBinary );
159 }
160 else if ( EQUAL( pszTypName, "date" ) )
161 {
162 oField.SetType( OFTDate );
163 }
164 else if ( EQUAL( pszTypName, "datetime" ) )
165 {
166 oField.SetType( OFTDateTime );
167 }
168 else if ( EQUAL( pszTypName, "decimal" ) ||
169 EQUAL( pszTypName, "money" ) ||
170 EQUAL( pszTypName, "float" ) ||
171 EQUAL( pszTypName, "smallfloat" ) )
172 {
173 oField.SetType( OFTReal );
174 oField.SetPrecision( MAX( 0, poTI->Scale() ) ); // -1 for numeric
175 }
176 else if ( EQUAL( pszTypName, "integer" ) ||
177 EQUAL( pszTypName, "serial" ) )
178 {
179 oField.SetType( OFTInteger );
180 // 10 as hardcoded max int32 value length + 1 sig bit
181 oField.SetWidth( 11 );
182 }
183 else if ( EQUAL( pszTypName, "smallint" ) )
184 {
185 oField.SetType( OFTInteger );
186 // 5 as hardcoded max int16 value length + 1 sig bit
187 oField.SetWidth( 6 );
188 }
189 else
190 {
191 // leave as string:
192 // *char, character, character varing, *varchar
193 // interval. int8, serial8
194 }
195
196 poFeatureDefn->AddFieldDefn( &oField );
197 }
198
199 /* -------------------------------------------------------------------- */
200 /* If we don't already have an FID, check if there is a special */
201 /* FID named column available. */
202 /* -------------------------------------------------------------------- */
203 if( pszFIDColumn == NULL )
204 {
205 const char *pszOGR_FID = CPLGetConfigOption("IDB_OGR_FID","OGR_FID");
206 if( poFeatureDefn->GetFieldIndex( pszOGR_FID ) != -1 )
207 pszFIDColumn = CPLStrdup(pszOGR_FID);
208 }
209
210 if( pszFIDColumn != NULL )
211 CPLDebug( "OGR_IDB", "Using column %s as FID for table %s.",
212 pszFIDColumn, poFeatureDefn->GetName() );
213 else
214 CPLDebug( "OGR_IDB", "Table %s has no identified FID column.",
215 poFeatureDefn->GetName() );
216
217 return CE_None;
218 }
219
220
221 /************************************************************************/
222 /* ResetReading() */
223 /************************************************************************/
224
ResetReading()225 void OGRIDBLayer::ResetReading()
226
227 {
228 iNextShapeId = 0;
229 }
230
231 /************************************************************************/
232 /* GetNextFeature() */
233 /************************************************************************/
234
GetNextFeature()235 OGRFeature *OGRIDBLayer::GetNextFeature()
236
237 {
238 for( ; TRUE; )
239 {
240 OGRFeature *poFeature;
241
242 poFeature = GetNextRawFeature();
243 if( poFeature == NULL )
244 return NULL;
245
246 if( (m_poFilterGeom == NULL
247 || FilterGeometry( poFeature->GetGeometryRef() ) )
248 && (m_poAttrQuery == NULL
249 || m_poAttrQuery->Evaluate( poFeature )) )
250 return poFeature;
251
252 delete poFeature;
253 }
254 }
255
256 /************************************************************************/
257 /* GetNextRawFeature() */
258 /************************************************************************/
259
GetNextRawFeature()260 OGRFeature *OGRIDBLayer::GetNextRawFeature()
261
262 {
263 if( GetQuery() == NULL )
264 return NULL;
265
266 /* -------------------------------------------------------------------- */
267 /* If we are marked to restart then do so, and fetch a record. */
268 /* -------------------------------------------------------------------- */
269 ITRow * row = poCurr->NextRow();
270 if ( ! row )
271 {
272 delete poCurr;
273 poCurr = NULL;
274 return NULL;
275 }
276
277 iNextShapeId++;
278 m_nFeaturesRead++;
279
280 /* -------------------------------------------------------------------- */
281 /* Create a feature from the current result. */
282 /* -------------------------------------------------------------------- */
283 int iField;
284 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
285
286 const ITTypeInfo * poRowType = poCurr->RowType();
287 int nFieldCount = poRowType->ColumnCount();
288
289 for ( iField = 0; iField < nFieldCount; iField++ )
290 {
291 /* -------------------------------------------------------------------- */
292 /* Handle FID column */
293 /* -------------------------------------------------------------------- */
294 if ( pszFIDColumn != NULL &&
295 EQUAL( poRowType->ColumnName( iField ), pszFIDColumn ) )
296 poFeature->SetFID( atoi( row->Column( iField )->Printable() ) );
297
298 /* -------------------------------------------------------------------- */
299 /* Handle geometry */
300 /* -------------------------------------------------------------------- */
301 if( pszGeomColumn != NULL &&
302 EQUAL( poRowType->ColumnName( iField ), pszGeomColumn ) )
303 {
304 OGRGeometry *poGeom = NULL;
305 OGRErr eErr = OGRERR_NONE;
306
307 ITValue * v = row->Column( iField );
308
309 if( ! v->IsNull() && ! bGeomColumnWKB )
310 {
311 const char *pszGeomText = v->Printable();
312 if ( pszGeomText != NULL )
313 eErr =
314 OGRGeometryFactory::createFromWkt((char **) &pszGeomText,
315 poSRS, &poGeom);
316 }
317 else if( ! v->IsNull() && bGeomColumnWKB )
318 {
319 ITDatum *rv = 0;
320 if ( v->QueryInterface( ITDatumIID, (void **) &rv ) ==
321 IT_QUERYINTERFACE_SUCCESS )
322 {
323 int nLength = rv->DataLength();
324 unsigned char * wkb = (unsigned char *)rv->Data();
325
326 eErr = OGRGeometryFactory::createFromWkb( wkb, poSRS, &poGeom, nLength);
327 rv->Release();
328 }
329 }
330
331 v->Release();
332
333
334 if ( eErr != OGRERR_NONE )
335 {
336 const char *pszMessage;
337
338 switch ( eErr )
339 {
340 case OGRERR_NOT_ENOUGH_DATA:
341 pszMessage = "Not enough data to deserialize";
342 break;
343 case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
344 pszMessage = "Unsupported geometry type";
345 break;
346 case OGRERR_CORRUPT_DATA:
347 pszMessage = "Corrupt data";
348 default:
349 pszMessage = "Unrecognized error";
350 }
351 CPLError(CE_Failure, CPLE_AppDefined,
352 "GetNextRawFeature(): %s", pszMessage);
353 }
354
355 if( poGeom != NULL )
356 {
357 poFeature->SetGeometryDirectly( poGeom );
358 }
359
360 continue;
361 }
362
363 /* -------------------------------------------------------------------- */
364 /* Transfer regular data fields. */
365 /* -------------------------------------------------------------------- */
366 int iOGRField =
367 poFeatureDefn->GetFieldIndex( poRowType->ColumnName( iField ) );
368
369 if( iOGRField < 0 )
370 continue;
371
372 const char * pszColData = row->Column( iField )->Printable();
373
374 if( ! pszColData )
375 continue;
376
377 if( poFeatureDefn->GetFieldDefn(iOGRField)->GetType() == OFTBinary )
378 poFeature->SetField( iOGRField,
379 poRowType->ColumnType( iField )->Size(),
380 (GByte *) pszColData );
381 else
382 poFeature->SetField( iOGRField, pszColData );
383 }
384
385 row->Release();
386 return poFeature;
387 }
388
389 /************************************************************************/
390 /* GetFeature() */
391 /************************************************************************/
392
GetFeature(GIntBig nFeatureId)393 OGRFeature *OGRIDBLayer::GetFeature( GIntBig nFeatureId )
394
395 {
396 /* This should be implemented directly! */
397
398 return OGRLayer::GetFeature( nFeatureId );
399 }
400
401 /************************************************************************/
402 /* TestCapability() */
403 /************************************************************************/
404
TestCapability(const char * pszCap)405 int OGRIDBLayer::TestCapability( const char * pszCap )
406
407 {
408 if( EQUAL(pszCap,OLCRandomRead) )
409 return FALSE;
410
411 else if( EQUAL(pszCap,OLCFastFeatureCount) )
412 return FALSE;
413
414 else if( EQUAL(pszCap,OLCFastSpatialFilter) )
415 return FALSE;
416
417 else if( EQUAL(pszCap,OLCTransactions) )
418 return FALSE;
419
420 else
421 return FALSE;
422 }
423
424 /************************************************************************/
425 /* GetSpatialRef() */
426 /************************************************************************/
427
GetSpatialRef()428 OGRSpatialReference *OGRIDBLayer::GetSpatialRef()
429
430 {
431 return poSRS;
432 }
433
434 /************************************************************************/
435 /* GetFIDColumn() */
436 /************************************************************************/
437
GetFIDColumn()438 const char *OGRIDBLayer::GetFIDColumn()
439
440 {
441 if( pszFIDColumn != NULL )
442 return pszFIDColumn;
443 else
444 return "";
445 }
446
447 /************************************************************************/
448 /* GetGeometryColumn() */
449 /************************************************************************/
450
GetGeometryColumn()451 const char *OGRIDBLayer::GetGeometryColumn()
452
453 {
454 if( pszGeomColumn != NULL )
455 return pszGeomColumn;
456 else
457 return "";
458 }
459
460 /* TODO Query to get layer extent */
461 /*
462 EXECUTE FUNCTION SE_BoundingBox ('table_name', 'geom_column' )
463 */
464