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