1 /******************************************************************************
2 *
3 * Project: OpenGIS Simple Features Reference Implementation
4 * Purpose: Implements OGRIDBLayer class, code shared between
5 * the direct table access, and the generic SQL results
6 * (based on ODBC and PG drivers).
7 * Author: Oleg Semykin, oleg.semykin@gmail.com
8 *
9 ******************************************************************************
10 * Copyright (c) 2006, Oleg Semykin
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_idb.h"
33 #include "cpl_string.h"
34
35 CPL_CVSID("$Id: ogridblayer.cpp 417b66cdf50174fe8d59833c93710813f205d9ba 2020-08-30 12:18:19 +0200 Even Rouault $")
36
37 /************************************************************************/
38 /* OGRIDBLayer() */
~OGRIDBDriver()39 /************************************************************************/
40
41 OGRIDBLayer::OGRIDBLayer()
42
43 {
44 poDS = nullptr;
45
46 bGeomColumnWKB = FALSE;
47 pszFIDColumn = nullptr;
48 pszGeomColumn = nullptr;
49
50 m_poCurr = nullptr;
51
52 iNextShapeId = 0;
53
54 poSRS = nullptr;
55 nSRSId = -2; // we haven't even queried the database for it yet.
56 poFeatureDefn = nullptr;
57 }
Open(const char * pszFilename,int bUpdate)58
59 /************************************************************************/
60 /* ~OGRIDBLayer() */
61 /************************************************************************/
62
63 OGRIDBLayer::~OGRIDBLayer()
64
65 {
66 if( m_poCurr != nullptr )
67 {
68 m_poCurr->Close();
69 delete m_poCurr;
70 m_poCurr = nullptr;
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 = nullptr;
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
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++ )
TestCapability(const char * pszCap)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 != nullptr && EQUAL(pszColName,pszGeomColumn) )
118 continue;
119
120 if ( STARTS_WITH_CI(pszTypName, "st_") && pszGeomColumn == nullptr )
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 STARTS_WITH_CI(pszTypName, "list") ||
147 STARTS_WITH_CI(pszTypName, "collection") ||
148 STARTS_WITH_CI(pszTypName, "row") ||
149 STARTS_WITH_CI(pszTypName, "set") )
150 {
151 CPLDebug( "OGR_IDB", "'%s' column type not supported yet. Column '%s'",
152 pszTypName, pszColName );
153 continue;
154 }
155
156 if ( STARTS_WITH_CI(pszTypName, "st_") )
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 varying, *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 == nullptr )
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 != nullptr )
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 /* ResetReading() */
222 /************************************************************************/
223
224 void OGRIDBLayer::ResetReading()
225
226 {
227 iNextShapeId = 0;
228 }
229
230 /************************************************************************/
231 /* GetNextFeature() */
232 /************************************************************************/
233
234 OGRFeature *OGRIDBLayer::GetNextFeature()
235
236 {
237 while( true )
238 {
239 OGRFeature *poFeature;
240
241 poFeature = GetNextRawFeature();
242 if( poFeature == nullptr )
243 return nullptr;
244
245 if( (m_poFilterGeom == nullptr
246 || FilterGeometry( poFeature->GetGeometryRef() ) )
247 && (m_poAttrQuery == nullptr
248 || m_poAttrQuery->Evaluate( poFeature )) )
249 return poFeature;
250
251 delete poFeature;
252 }
253 }
254
255 /************************************************************************/
256 /* GetNextRawFeature() */
257 /************************************************************************/
258
259 OGRFeature *OGRIDBLayer::GetNextRawFeature()
260
261 {
262 if( GetQuery() == nullptr )
263 return nullptr;
264
265 /* -------------------------------------------------------------------- */
266 /* If we are marked to restart then do so, and fetch a record. */
267 /* -------------------------------------------------------------------- */
268 ITRow * row = m_poCurr->NextRow();
269 if ( ! row )
270 {
271 delete m_poCurr;
272 m_poCurr = nullptr;
273 return nullptr;
274 }
275
276 iNextShapeId++;
277 m_nFeaturesRead++;
278
279 /* -------------------------------------------------------------------- */
280 /* Create a feature from the current result. */
281 /* -------------------------------------------------------------------- */
282 int iField;
283 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
284
285 const ITTypeInfo * poRowType = m_poCurr->RowType();
286 int nFieldCount = poRowType->ColumnCount();
287
288 for ( iField = 0; iField < nFieldCount; iField++ )
289 {
290 /* -------------------------------------------------------------------- */
291 /* Handle FID column */
292 /* -------------------------------------------------------------------- */
293 if ( pszFIDColumn != nullptr &&
294 EQUAL( poRowType->ColumnName( iField ), pszFIDColumn ) )
295 poFeature->SetFID( atoi( row->Column( iField )->Printable() ) );
296
297 /* -------------------------------------------------------------------- */
298 /* Handle geometry */
299 /* -------------------------------------------------------------------- */
300 if( pszGeomColumn != nullptr &&
301 EQUAL( poRowType->ColumnName( iField ), pszGeomColumn ) )
302 {
303 OGRGeometry *poGeom = nullptr;
304 OGRErr eErr = OGRERR_NONE;
305
306 ITValue * v = row->Column( iField );
307
308 if( ! v->IsNull() && ! bGeomColumnWKB )
309 {
310 const char *pszGeomText = v->Printable();
311 if ( pszGeomText != nullptr )
312 eErr =
313 OGRGeometryFactory::createFromWkt(pszGeomText,
314 poSRS, &poGeom);
315 }
316 else if( ! v->IsNull() && bGeomColumnWKB )
317 {
318 ITDatum *rv = nullptr;
319 if ( v->QueryInterface( ITDatumIID, (void **) &rv ) ==
320 IT_QUERYINTERFACE_SUCCESS )
321 {
322 int nLength = rv->DataLength();
323 unsigned char * wkb = (unsigned char *)rv->Data();
324
325 eErr = OGRGeometryFactory::createFromWkb( wkb, poSRS, &poGeom, nLength);
326 rv->Release();
327 }
328 }
329
330 v->Release();
331
332 if ( eErr != OGRERR_NONE )
333 {
334 const char *pszMessage;
335
336 switch ( eErr )
337 {
338 case OGRERR_NOT_ENOUGH_DATA:
339 pszMessage = "Not enough data to deserialize";
340 break;
341 case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
342 pszMessage = "Unsupported geometry type";
343 break;
344 case OGRERR_CORRUPT_DATA:
345 pszMessage = "Corrupt data";
346 break;
347 default:
348 pszMessage = "Unrecognized error";
349 }
350 CPLError(CE_Failure, CPLE_AppDefined,
351 "GetNextRawFeature(): %s", pszMessage);
352 }
353
354 if( poGeom != nullptr )
355 {
356 poFeature->SetGeometryDirectly( poGeom );
357 }
358
359 continue;
360 }
361
362 /* -------------------------------------------------------------------- */
363 /* Transfer regular data fields. */
364 /* -------------------------------------------------------------------- */
365 int iOGRField =
366 poFeatureDefn->GetFieldIndex( poRowType->ColumnName( iField ) );
367
368 if( iOGRField < 0 )
369 continue;
370
371 const char * pszColData = row->Column( iField )->Printable();
372
373 if( ! pszColData )
374 continue;
375
376 if( poFeatureDefn->GetFieldDefn(iOGRField)->GetType() == OFTBinary )
377 poFeature->SetField( iOGRField,
378 poRowType->ColumnType( iField )->Size(),
379 (GByte *) pszColData );
380 else
381 poFeature->SetField( iOGRField, pszColData );
382 }
383
384 row->Release();
385 return poFeature;
386 }
387
388 /************************************************************************/
389 /* GetFeature() */
390 /************************************************************************/
391
392 OGRFeature *OGRIDBLayer::GetFeature( GIntBig nFeatureId )
393
394 {
395 /* This should be implemented directly! */
396
397 return OGRLayer::GetFeature( nFeatureId );
398 }
399
400 /************************************************************************/
401 /* TestCapability() */
402 /************************************************************************/
403
404 int OGRIDBLayer::TestCapability( const char * /*pszCap*/ )
405
406 {
407 return FALSE;
408 }
409
410 /************************************************************************/
411 /* GetSpatialRef() */
412 /************************************************************************/
413
414 OGRSpatialReference *OGRIDBLayer::GetSpatialRef()
415
416 {
417 return poSRS;
418 }
419
420 /************************************************************************/
421 /* GetFIDColumn() */
422 /************************************************************************/
423
424 const char *OGRIDBLayer::GetFIDColumn()
425
426 {
427 if( pszFIDColumn != nullptr )
428 return pszFIDColumn;
429 else
430 return "";
431 }
432
433 /************************************************************************/
434 /* GetGeometryColumn() */
435 /************************************************************************/
436
437 const char *OGRIDBLayer::GetGeometryColumn()
438
439 {
440 if( pszGeomColumn != nullptr )
441 return pszGeomColumn;
442 else
443 return "";
444 }
445
446 /* TODO Query to get layer extent */
447 /*
448 EXECUTE FUNCTION SE_BoundingBox ('table_name', 'geom_column' )
449 */
450