1 : /******************************************************************************
2 : * $Id: ogrmdblayer.cpp 22156 2011-04-13 20:08:07Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRMDBLayer class
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2011, Even Rouault, <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_mdb.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "ogrpgeogeometry.h"
34 : #include "ogrgeomediageometry.h"
35 :
36 : CPL_CVSID("$Id: ogrmdblayer.cpp 22156 2011-04-13 20:08:07Z rouault $");
37 :
38 : /************************************************************************/
39 : /* OGRMDBLayer() */
40 : /************************************************************************/
41 :
42 18 : OGRMDBLayer::OGRMDBLayer(OGRMDBDataSource* poDS, OGRMDBTable* poMDBTable)
43 :
44 : {
45 18 : this->poDS = poDS;
46 18 : this->poMDBTable = poMDBTable;
47 :
48 18 : eGeometryType = MDB_GEOM_NONE;
49 :
50 18 : iGeomColumn = -1;
51 18 : pszGeomColumn = NULL;
52 18 : pszFIDColumn = NULL;
53 :
54 18 : panFieldOrdinals = NULL;
55 :
56 18 : poFeatureDefn = NULL;
57 :
58 18 : iNextShapeId = 0;
59 :
60 18 : poSRS = NULL;
61 18 : nSRSId = -2; // we haven't even queried the database for it yet.
62 :
63 18 : bHasExtent = FALSE;
64 18 : }
65 :
66 : /************************************************************************/
67 : /* ~OGRMDBLayer() */
68 : /************************************************************************/
69 :
70 18 : OGRMDBLayer::~OGRMDBLayer()
71 :
72 : {
73 18 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
74 : {
75 : CPLDebug( "MDB", "%d features read on layer '%s'.",
76 : (int) m_nFeaturesRead,
77 9 : poFeatureDefn->GetName() );
78 : }
79 :
80 18 : if( poFeatureDefn != NULL )
81 : {
82 18 : poFeatureDefn->Release();
83 18 : poFeatureDefn = NULL;
84 : }
85 :
86 18 : CPLFree( pszGeomColumn );
87 18 : CPLFree( pszFIDColumn );
88 :
89 18 : CPLFree( panFieldOrdinals );
90 :
91 18 : if( poSRS != NULL )
92 : {
93 18 : poSRS->Release();
94 18 : poSRS = NULL;
95 : }
96 :
97 18 : delete poMDBTable;
98 18 : }
99 :
100 : /************************************************************************/
101 : /* BuildFeatureDefn() */
102 : /* */
103 : /* Build feature definition from a set of column definitions */
104 : /* set on a statement. Sift out geometry and FID fields. */
105 : /************************************************************************/
106 :
107 18 : CPLErr OGRMDBLayer::BuildFeatureDefn()
108 :
109 : {
110 18 : poFeatureDefn = new OGRFeatureDefn( poMDBTable->GetName() );
111 :
112 18 : poFeatureDefn->Reference();
113 :
114 :
115 18 : int nRawColumns = poMDBTable->GetColumnCount();
116 18 : panFieldOrdinals = (int *) CPLMalloc( sizeof(int) * nRawColumns );
117 :
118 18 : for( int iCol = 0; iCol < nRawColumns; iCol++ )
119 : {
120 120 : const char* pszColName = poMDBTable->GetColumnName(iCol);
121 120 : OGRFieldDefn oField(pszColName, OFTString );
122 :
123 120 : if( pszGeomColumn != NULL
124 : && EQUAL(pszColName,pszGeomColumn) )
125 18 : continue;
126 :
127 102 : if( eGeometryType == MDB_GEOM_PGEO
128 : && pszFIDColumn == NULL
129 : && EQUAL(pszColName,"OBJECTID") )
130 : {
131 18 : pszFIDColumn = CPLStrdup(pszColName);
132 : }
133 :
134 102 : if( eGeometryType == MDB_GEOM_PGEO
135 : && pszGeomColumn == NULL
136 : && EQUAL(pszColName,"Shape") )
137 : {
138 0 : pszGeomColumn = CPLStrdup(pszColName);
139 0 : continue;
140 : }
141 :
142 102 : switch( poMDBTable->GetColumnType(iCol) )
143 : {
144 : case MDB_Boolean:
145 0 : oField.SetType( OFTInteger );
146 0 : oField.SetWidth(1);
147 0 : break;
148 :
149 : case MDB_Byte:
150 : case MDB_Short:
151 : case MDB_Int:
152 18 : oField.SetType( OFTInteger );
153 18 : break;
154 :
155 : case MDB_Binary:
156 : case MDB_OLE:
157 0 : oField.SetType( OFTBinary );
158 0 : break;
159 :
160 : case MDB_Float:
161 : case MDB_Double:
162 36 : oField.SetType( OFTReal );
163 36 : break;
164 :
165 : case MDB_Text:
166 48 : oField.SetWidth(poMDBTable->GetColumnLength(iCol));
167 : break;
168 :
169 : default:
170 : /* leave it as OFTString */;
171 : }
172 :
173 102 : poFeatureDefn->AddFieldDefn( &oField );
174 102 : panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol+1;
175 : }
176 :
177 18 : return CE_None;
178 : }
179 :
180 :
181 : /************************************************************************/
182 : /* ResetReading() */
183 : /************************************************************************/
184 :
185 145 : void OGRMDBLayer::ResetReading()
186 :
187 : {
188 145 : iNextShapeId = 0;
189 145 : poMDBTable->ResetReading();
190 145 : }
191 :
192 : /************************************************************************/
193 : /* GetFeatureCount() */
194 : /************************************************************************/
195 :
196 37 : int OGRMDBLayer::GetFeatureCount(int bForce)
197 : {
198 37 : if (m_poFilterGeom != NULL || m_poAttrQuery != NULL)
199 17 : return OGRLayer::GetFeatureCount(bForce);
200 20 : return poMDBTable->GetRowCount();
201 : }
202 :
203 : /************************************************************************/
204 : /* GetNextFeature() */
205 : /************************************************************************/
206 :
207 273556 : OGRFeature *OGRMDBLayer::GetNextFeature()
208 :
209 : {
210 96767 : for( ; TRUE; )
211 : {
212 : OGRFeature *poFeature;
213 :
214 273556 : poFeature = GetNextRawFeature();
215 273556 : if( poFeature == NULL )
216 54 : return NULL;
217 :
218 273502 : if( (m_poFilterGeom == NULL
219 : || FilterGeometry( poFeature->GetGeometryRef() ) )
220 : && (m_poAttrQuery == NULL
221 : || m_poAttrQuery->Evaluate( poFeature )) )
222 176735 : return poFeature;
223 :
224 96767 : delete poFeature;
225 : }
226 : }
227 :
228 : /************************************************************************/
229 : /* GetNextRawFeature() */
230 : /************************************************************************/
231 :
232 273556 : OGRFeature *OGRMDBLayer::GetNextRawFeature()
233 :
234 : {
235 273556 : OGRErr err = OGRERR_NONE;
236 :
237 273556 : if( !poMDBTable->GetNextRow() )
238 54 : return NULL;
239 :
240 : /* -------------------------------------------------------------------- */
241 : /* Create a feature from the current result. */
242 : /* -------------------------------------------------------------------- */
243 : int iField;
244 273502 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
245 :
246 547004 : if( pszFIDColumn != NULL && poMDBTable->GetColumnIndex(pszFIDColumn) > -1 )
247 : poFeature->SetFID(
248 273502 : poMDBTable->GetColumnAsInt(poMDBTable->GetColumnIndex(pszFIDColumn)) );
249 : else
250 0 : poFeature->SetFID( iNextShapeId );
251 :
252 273502 : iNextShapeId++;
253 273502 : m_nFeaturesRead++;
254 :
255 : /* -------------------------------------------------------------------- */
256 : /* Set the fields. */
257 : /* -------------------------------------------------------------------- */
258 1914046 : for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
259 : {
260 1640544 : int iSrcField = panFieldOrdinals[iField]-1;
261 1640544 : char *pszValue = poMDBTable->GetColumnAsString( iSrcField );
262 1640544 : OGRFieldType eType = poFeature->GetFieldDefnRef(iField)->GetType();
263 :
264 1640544 : if( pszValue == NULL )
265 : /* no value */;
266 1640544 : else if( eType == OFTBinary )
267 : {
268 0 : int nBytes = 0;
269 0 : GByte* pData = poMDBTable->GetColumnAsBinary( iSrcField, &nBytes);
270 : poFeature->SetField( iField,
271 : nBytes,
272 0 : pData );
273 0 : CPLFree(pData);
274 : }
275 1640544 : else if ( eType == OFTInteger && EQUAL(pszValue, "true"))
276 : {
277 0 : poFeature->SetField( iField, 1 );
278 : }
279 : else
280 : {
281 1640544 : poFeature->SetField( iField, pszValue );
282 : }
283 :
284 1640544 : CPLFree(pszValue);
285 : }
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* Try to extract a geometry. */
289 : /* -------------------------------------------------------------------- */
290 547004 : if( eGeometryType == MDB_GEOM_PGEO && iGeomColumn >= 0)
291 : {
292 273502 : int nBytes = 0;
293 273502 : GByte* pData = poMDBTable->GetColumnAsBinary( iGeomColumn, &nBytes);
294 273502 : OGRGeometry *poGeom = NULL;
295 :
296 273502 : if( pData != NULL )
297 : {
298 273502 : err = OGRCreateFromShapeBin( pData, &poGeom, nBytes );
299 273502 : if( OGRERR_NONE != err )
300 : {
301 : CPLDebug( "MDB",
302 : "Translation shape binary to OGR geometry failed (FID=%ld)",
303 0 : (long)poFeature->GetFID() );
304 : }
305 : }
306 :
307 273502 : CPLFree(pData);
308 :
309 273502 : if( poGeom != NULL && OGRERR_NONE == err )
310 : {
311 273502 : poGeom->assignSpatialReference( poSRS );
312 273502 : poFeature->SetGeometryDirectly( poGeom );
313 : }
314 : }
315 0 : else if( eGeometryType == MDB_GEOM_GEOMEDIA && iGeomColumn >= 0)
316 : {
317 0 : int nBytes = 0;
318 0 : GByte* pData = poMDBTable->GetColumnAsBinary( iGeomColumn, &nBytes);
319 0 : OGRGeometry *poGeom = NULL;
320 :
321 0 : if( pData != NULL )
322 : {
323 0 : err = OGRCreateFromGeomedia( pData, &poGeom, nBytes );
324 0 : if( OGRERR_NONE != err )
325 : {
326 : CPLDebug( "MDB",
327 : "Translation geomedia binary to OGR geometry failed (FID=%ld)",
328 0 : (long)poFeature->GetFID() );
329 : }
330 : }
331 :
332 0 : CPLFree(pData);
333 :
334 0 : if( poGeom != NULL && OGRERR_NONE == err )
335 : {
336 0 : poGeom->assignSpatialReference( poSRS );
337 0 : poFeature->SetGeometryDirectly( poGeom );
338 : }
339 : }
340 :
341 273502 : return poFeature;
342 : }
343 :
344 : /************************************************************************/
345 : /* GetFeature() */
346 : /************************************************************************/
347 :
348 9 : OGRFeature *OGRMDBLayer::GetFeature( long nFeatureId )
349 :
350 : {
351 : /* This should be implemented directly! */
352 :
353 9 : return OGRLayer::GetFeature( nFeatureId );
354 : }
355 :
356 : /************************************************************************/
357 : /* TestCapability() */
358 : /************************************************************************/
359 :
360 26 : int OGRMDBLayer::TestCapability( const char * pszCap )
361 :
362 : {
363 : /*if( EQUAL(pszCap,OLCRandomRead) )
364 : return TRUE;
365 :
366 : else*/
367 26 : if( EQUAL(pszCap,OLCFastFeatureCount) ||
368 : EQUAL(pszCap,OLCFastGetExtent) )
369 0 : return m_poFilterGeom == NULL && m_poAttrQuery == NULL;
370 :
371 : else
372 26 : return FALSE;
373 : }
374 :
375 : /************************************************************************/
376 : /* GetSpatialRef() */
377 : /************************************************************************/
378 :
379 4 : OGRSpatialReference *OGRMDBLayer::GetSpatialRef()
380 :
381 : {
382 4 : return poSRS;
383 : }
384 :
385 : /************************************************************************/
386 : /* LookupSRID() */
387 : /************************************************************************/
388 :
389 18 : void OGRMDBLayer::LookupSRID( int nSRID )
390 :
391 : {
392 : /* -------------------------------------------------------------------- */
393 : /* Fetch the corresponding WKT from the SpatialRef table. */
394 : /* -------------------------------------------------------------------- */
395 18 : OGRMDBDatabase* poDB = poMDBTable->GetDB();
396 18 : OGRMDBTable* poSRSTable = poDB->GetTable("GDB_SpatialRefs");
397 18 : if (poSRSTable == NULL)
398 0 : return;
399 :
400 18 : int iSRTEXT = poSRSTable->GetColumnIndex("SRTEXT", TRUE);
401 18 : int iSRID = poSRSTable->GetColumnIndex("SRID", TRUE);
402 :
403 18 : if (iSRTEXT < 0 || iSRID < 0)
404 : {
405 0 : delete poSRSTable;
406 0 : return;
407 : }
408 :
409 18 : char* pszSRText = NULL;
410 36 : while(poSRSTable->GetNextRow())
411 : {
412 18 : int nTableSRID = poSRSTable->GetColumnAsInt(iSRID);
413 18 : if (nTableSRID == nSRID)
414 : {
415 18 : pszSRText = poSRSTable->GetColumnAsString(iSRTEXT);
416 18 : break;
417 : }
418 : }
419 :
420 18 : if (pszSRText == NULL)
421 : {
422 0 : delete poSRSTable;
423 0 : return;
424 : }
425 :
426 : /* -------------------------------------------------------------------- */
427 : /* Check that it isn't just a GUID. We don't know how to */
428 : /* translate those. */
429 : /* -------------------------------------------------------------------- */
430 :
431 18 : if( pszSRText[0] == '{' )
432 : {
433 0 : CPLDebug( "MDB", "Ignoreing GUID SRTEXT: %s", pszSRText );
434 0 : delete poSRSTable;
435 0 : CPLFree(pszSRText);
436 0 : return;
437 : }
438 :
439 : /* -------------------------------------------------------------------- */
440 : /* Turn it into an OGRSpatialReference. */
441 : /* -------------------------------------------------------------------- */
442 18 : poSRS = new OGRSpatialReference();
443 :
444 18 : char* pszSRTextPtr = pszSRText;
445 18 : if( poSRS->importFromWkt( &pszSRTextPtr ) != OGRERR_NONE )
446 : {
447 : CPLError( CE_Failure, CPLE_AppDefined,
448 : "importFromWKT() failed on SRS '%s'.",
449 0 : pszSRText);
450 0 : delete poSRS;
451 0 : poSRS = NULL;
452 : }
453 18 : else if( poSRS->morphFromESRI() != OGRERR_NONE )
454 : {
455 : CPLError( CE_Failure, CPLE_AppDefined,
456 0 : "morphFromESRI() failed on SRS." );
457 0 : delete poSRS;
458 0 : poSRS = NULL;
459 : }
460 : else
461 18 : nSRSId = nSRID;
462 :
463 18 : delete poSRSTable;
464 18 : CPLFree(pszSRText);
465 : }
466 :
467 : /************************************************************************/
468 : /* GetFIDColumn() */
469 : /************************************************************************/
470 :
471 0 : const char *OGRMDBLayer::GetFIDColumn()
472 :
473 : {
474 0 : if( pszFIDColumn != NULL )
475 0 : return pszFIDColumn;
476 : else
477 0 : return "";
478 : }
479 :
480 : /************************************************************************/
481 : /* GetGeometryColumn() */
482 : /************************************************************************/
483 :
484 0 : const char *OGRMDBLayer::GetGeometryColumn()
485 :
486 : {
487 0 : if( pszGeomColumn != NULL )
488 0 : return pszGeomColumn;
489 : else
490 0 : return "";
491 : }
492 :
493 :
494 : /************************************************************************/
495 : /* Initialize() */
496 : /************************************************************************/
497 :
498 18 : CPLErr OGRMDBLayer::Initialize( const char *pszTableName,
499 : const char *pszGeomCol,
500 : int nShapeType,
501 : double dfExtentLeft,
502 : double dfExtentRight,
503 : double dfExtentBottom,
504 : double dfExtentTop,
505 : int nSRID,
506 : int bHasZ )
507 :
508 :
509 : {
510 18 : CPLFree( pszGeomColumn );
511 :
512 18 : if( pszGeomCol == NULL )
513 0 : pszGeomColumn = NULL;
514 : else
515 : {
516 18 : pszGeomColumn = CPLStrdup( pszGeomCol );
517 18 : iGeomColumn = poMDBTable->GetColumnIndex( pszGeomColumn );
518 : }
519 :
520 18 : CPLFree( pszFIDColumn );
521 18 : pszFIDColumn = NULL;
522 :
523 18 : bHasExtent = TRUE;
524 18 : sExtent.MinX = dfExtentLeft;
525 18 : sExtent.MaxX = dfExtentRight;
526 18 : sExtent.MinY = dfExtentBottom;
527 18 : sExtent.MaxY = dfExtentTop;
528 :
529 18 : LookupSRID( nSRID );
530 :
531 18 : eGeometryType = MDB_GEOM_PGEO;
532 :
533 : CPLErr eErr;
534 18 : eErr = BuildFeatureDefn();
535 18 : if( eErr != CE_None )
536 0 : return eErr;
537 :
538 : /* -------------------------------------------------------------------- */
539 : /* Setup geometry type. */
540 : /* -------------------------------------------------------------------- */
541 : OGRwkbGeometryType eOGRType;
542 :
543 18 : switch( nShapeType )
544 : {
545 : case ESRI_LAYERGEOMTYPE_NULL:
546 0 : eOGRType = wkbNone;
547 0 : break;
548 :
549 : case ESRI_LAYERGEOMTYPE_POINT:
550 6 : eOGRType = wkbPoint;
551 6 : break;
552 :
553 : case ESRI_LAYERGEOMTYPE_MULTIPOINT:
554 0 : eOGRType = wkbMultiPoint;
555 0 : break;
556 :
557 : case ESRI_LAYERGEOMTYPE_POLYLINE:
558 6 : eOGRType = wkbLineString;
559 6 : break;
560 :
561 : case ESRI_LAYERGEOMTYPE_POLYGON:
562 : case ESRI_LAYERGEOMTYPE_MULTIPATCH:
563 6 : eOGRType = wkbPolygon;
564 6 : break;
565 :
566 : default:
567 0 : CPLDebug("MDB", "Unexpected value for shape type : %d", nShapeType);
568 0 : eOGRType = wkbUnknown;
569 : break;
570 : }
571 :
572 18 : if( eOGRType != wkbUnknown && eOGRType != wkbNone && bHasZ )
573 18 : eOGRType = (OGRwkbGeometryType)(((int) eOGRType) | wkb25DBit);
574 :
575 18 : poFeatureDefn->SetGeomType(eOGRType);
576 :
577 18 : return CE_None;
578 : }
579 :
580 :
581 : /************************************************************************/
582 : /* Initialize() */
583 : /************************************************************************/
584 :
585 0 : CPLErr OGRMDBLayer::Initialize( const char *pszTableName,
586 : const char *pszGeomCol,
587 : OGRSpatialReference* poSRS )
588 :
589 :
590 : {
591 0 : CPLFree( pszGeomColumn );
592 :
593 0 : if( pszGeomCol == NULL )
594 0 : pszGeomColumn = NULL;
595 : else
596 : {
597 0 : pszGeomColumn = CPLStrdup( pszGeomCol );
598 0 : iGeomColumn = poMDBTable->GetColumnIndex( pszGeomColumn );
599 : }
600 :
601 0 : CPLFree( pszFIDColumn );
602 0 : pszFIDColumn = NULL;
603 :
604 0 : eGeometryType = MDB_GEOM_GEOMEDIA;
605 :
606 0 : this->poSRS = poSRS;
607 :
608 : CPLErr eErr;
609 0 : eErr = BuildFeatureDefn();
610 0 : if( eErr != CE_None )
611 0 : return eErr;
612 :
613 0 : return CE_None;
614 : }
615 :
616 : /************************************************************************/
617 : /* GetExtent() */
618 : /************************************************************************/
619 :
620 4 : OGRErr OGRMDBLayer::GetExtent( OGREnvelope *psExtent, int bForce )
621 :
622 : {
623 4 : if (bHasExtent)
624 : {
625 4 : *psExtent = sExtent;
626 4 : return OGRERR_NONE;
627 : }
628 : else
629 : {
630 0 : return OGRLayer::GetExtent(psExtent, bForce);
631 : }
632 : }
|