1 : /******************************************************************************
2 : * $Id: ogrgeomediadatasource.cpp 21561 2011-01-23 12:22:58Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRGeomediaDataSource 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 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.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 "ogr_geomedia.h"
32 : #include "ogrgeomediageometry.h"
33 : #include "cpl_conv.h"
34 : #include "cpl_string.h"
35 : #include <vector>
36 :
37 : CPL_CVSID("$Id: ogrgeomediadatasource.cpp 21561 2011-01-23 12:22:58Z rouault $");
38 :
39 : /************************************************************************/
40 : /* OGRGeomediaDataSource() */
41 : /************************************************************************/
42 :
43 0 : OGRGeomediaDataSource::OGRGeomediaDataSource()
44 :
45 : {
46 0 : pszName = NULL;
47 0 : papoLayers = NULL;
48 0 : papoLayersInvisible = NULL;
49 0 : nLayers = 0;
50 0 : nLayersWithInvisible = 0;
51 0 : }
52 :
53 : /************************************************************************/
54 : /* ~OGRGeomediaDataSource() */
55 : /************************************************************************/
56 :
57 0 : OGRGeomediaDataSource::~OGRGeomediaDataSource()
58 :
59 : {
60 : int i;
61 :
62 0 : CPLFree( pszName );
63 :
64 0 : for( i = 0; i < nLayers; i++ )
65 0 : delete papoLayers[i];
66 0 : CPLFree( papoLayers );
67 :
68 0 : for( i = 0; i < nLayersWithInvisible; i++ )
69 0 : delete papoLayersInvisible[i];
70 0 : CPLFree( papoLayersInvisible );
71 0 : }
72 :
73 : /************************************************************************/
74 : /* CheckDSNStringTemplate() */
75 : /* The string will be used as the formatting argument of sprintf with */
76 : /* a string in vararg. So let's check there's only one '%s', and nothing*/
77 : /* else */
78 : /************************************************************************/
79 :
80 0 : static int CheckDSNStringTemplate(const char* pszStr)
81 : {
82 0 : int nPercentSFound = FALSE;
83 0 : while(*pszStr)
84 : {
85 0 : if (*pszStr == '%')
86 : {
87 0 : if (pszStr[1] != 's')
88 : {
89 0 : return FALSE;
90 : }
91 : else
92 : {
93 0 : if (nPercentSFound)
94 0 : return FALSE;
95 0 : nPercentSFound = TRUE;
96 : }
97 : }
98 0 : pszStr ++;
99 : }
100 0 : return TRUE;
101 : }
102 :
103 : /************************************************************************/
104 : /* Open() */
105 : /************************************************************************/
106 :
107 0 : int OGRGeomediaDataSource::Open( const char * pszNewName, int bUpdate,
108 : int bTestOpen )
109 :
110 : {
111 0 : CPLAssert( nLayers == 0 );
112 :
113 : /* -------------------------------------------------------------------- */
114 : /* If this is the name of an MDB file, then construct the */
115 : /* appropriate connection string. Otherwise clip of GEOMEDIA: to */
116 : /* get the DSN. */
117 : /* */
118 : /* -------------------------------------------------------------------- */
119 : char *pszDSN;
120 0 : if( EQUALN(pszNewName,"GEOMEDIA:",9) )
121 0 : pszDSN = CPLStrdup( pszNewName + 9 );
122 : else
123 : {
124 0 : const char *pszDSNStringTemplate = NULL;
125 0 : pszDSNStringTemplate = CPLGetConfigOption( "GEOMEDIA_DRIVER_TEMPLATE", "DRIVER=Microsoft Access Driver (*.mdb);DBQ=%s");
126 0 : if (!CheckDSNStringTemplate(pszDSNStringTemplate))
127 : {
128 : CPLError( CE_Failure, CPLE_AppDefined,
129 0 : "Illegal value for GEOMEDIA_DRIVER_TEMPLATE option");
130 0 : return FALSE;
131 : }
132 0 : pszDSN = (char *) CPLMalloc(strlen(pszNewName)+strlen(pszDSNStringTemplate)+100);
133 0 : sprintf( pszDSN, pszDSNStringTemplate, pszNewName );
134 : }
135 :
136 : /* -------------------------------------------------------------------- */
137 : /* Initialize based on the DSN. */
138 : /* -------------------------------------------------------------------- */
139 0 : CPLDebug( "Geomedia", "EstablishSession(%s)", pszDSN );
140 :
141 0 : if( !oSession.EstablishSession( pszDSN, NULL, NULL ) )
142 : {
143 : CPLError( CE_Failure, CPLE_AppDefined,
144 : "Unable to initialize ODBC connection to DSN for %s,\n"
145 0 : "%s", pszDSN, oSession.GetLastError() );
146 0 : CPLFree( pszDSN );
147 0 : return FALSE;
148 : }
149 :
150 0 : CPLFree( pszDSN );
151 :
152 0 : pszName = CPLStrdup( pszNewName );
153 :
154 0 : bDSUpdate = bUpdate;
155 :
156 : /* -------------------------------------------------------------------- */
157 : /* Collect list of tables and their supporting info from */
158 : /* GAliasTable. */
159 : /* -------------------------------------------------------------------- */
160 0 : CPLString osGFeaturesTable = GetTableNameFromType("INGRFeatures");
161 0 : if (osGFeaturesTable.size() == 0)
162 0 : return FALSE;
163 :
164 0 : CPLString osGeometryProperties = GetTableNameFromType("INGRGeometryProperties");
165 0 : CPLString osGCoordSystemTable = GetTableNameFromType("GCoordSystemTable");
166 :
167 0 : std::vector<char **> apapszGeomColumns;
168 : {
169 0 : CPLODBCStatement oStmt( &oSession );
170 0 : oStmt.Appendf( "SELECT FeatureName, PrimaryGeometryFieldName FROM %s", osGFeaturesTable.c_str() );
171 :
172 0 : if( !oStmt.ExecuteSQL() )
173 : {
174 : CPLDebug( "GEOMEDIA",
175 : "SELECT on %s fails, perhaps not a geomedia geodatabase?\n%s",
176 : osGFeaturesTable.c_str(),
177 0 : oSession.GetLastError() );
178 0 : return FALSE;
179 : }
180 :
181 0 : while( oStmt.Fetch() )
182 : {
183 0 : int i, iNew = apapszGeomColumns.size();
184 0 : char **papszRecord = NULL;
185 0 : for( i = 0; i < 2; i++ )
186 : papszRecord = CSLAddString( papszRecord,
187 0 : oStmt.GetColData(i) );
188 0 : apapszGeomColumns.resize(iNew+1);
189 0 : apapszGeomColumns[iNew] = papszRecord;
190 0 : }
191 : }
192 :
193 0 : std::vector<OGRSpatialReference*> apoSRS;
194 0 : if (osGeometryProperties.size() != 0 && osGCoordSystemTable.size() != 0)
195 : {
196 0 : std::vector<CPLString> aosGUID;
197 : {
198 0 : CPLODBCStatement oStmt( &oSession );
199 0 : oStmt.Appendf( "SELECT GCoordSystemGUID FROM %s", osGeometryProperties.c_str() );
200 :
201 0 : if( !oStmt.ExecuteSQL() )
202 : {
203 : CPLDebug( "GEOMEDIA",
204 : "SELECT on %s fails, perhaps not a geomedia geodatabase?\n%s",
205 : osGeometryProperties.c_str(),
206 0 : oSession.GetLastError() );
207 0 : return FALSE;
208 : }
209 :
210 0 : while( oStmt.Fetch() )
211 : {
212 0 : aosGUID.push_back(oStmt.GetColData(0));
213 : }
214 :
215 0 : if (apapszGeomColumns.size() != aosGUID.size())
216 : {
217 : CPLDebug( "GEOMEDIA", "%s and %s don't have the same size",
218 0 : osGFeaturesTable.c_str(), osGeometryProperties.c_str() );
219 0 : return FALSE;
220 0 : }
221 : }
222 :
223 : int i;
224 0 : for(i=0; i<(int)aosGUID.size();i++)
225 : {
226 0 : apoSRS.push_back(GetGeomediaSRS(osGCoordSystemTable, aosGUID[i]));
227 0 : }
228 : }
229 :
230 : /* -------------------------------------------------------------------- */
231 : /* Create a layer for each spatial table. */
232 : /* -------------------------------------------------------------------- */
233 : unsigned int iTable;
234 :
235 : papoLayers = (OGRGeomediaLayer **) CPLCalloc(apapszGeomColumns.size(),
236 0 : sizeof(void*));
237 :
238 0 : for( iTable = 0; iTable < apapszGeomColumns.size(); iTable++ )
239 : {
240 0 : char **papszRecord = apapszGeomColumns[iTable];
241 : OGRGeomediaTableLayer *poLayer;
242 :
243 0 : poLayer = new OGRGeomediaTableLayer( this );
244 :
245 0 : if( poLayer->Initialize( papszRecord[0], papszRecord[1], (apoSRS.size()) ? apoSRS[iTable] : NULL )
246 : != CE_None )
247 : {
248 0 : delete poLayer;
249 : }
250 : else
251 : {
252 0 : papoLayers[nLayers++] = poLayer;
253 : }
254 0 : CSLDestroy(papszRecord);
255 : }
256 :
257 0 : return TRUE;
258 : }
259 :
260 :
261 : /************************************************************************/
262 : /* GetTableNameFromType() */
263 : /************************************************************************/
264 :
265 0 : CPLString OGRGeomediaDataSource::GetTableNameFromType(const char* pszTableType)
266 : {
267 0 : CPLODBCStatement oStmt( &oSession );
268 :
269 0 : oStmt.Appendf( "SELECT TableName FROM GAliasTable WHERE TableType = '%s'", pszTableType );
270 :
271 0 : if( !oStmt.ExecuteSQL() )
272 : {
273 : CPLDebug( "GEOMEDIA",
274 : "SELECT for %s on GAliasTable fails, perhaps not a geomedia geodatabase?\n%s",
275 : pszTableType,
276 0 : oSession.GetLastError() );
277 0 : return "";
278 : }
279 :
280 0 : while( oStmt.Fetch() )
281 : {
282 0 : return oStmt.GetColData(0);
283 : }
284 :
285 0 : return "";
286 : }
287 :
288 :
289 : /************************************************************************/
290 : /* GetGeomediaSRS() */
291 : /************************************************************************/
292 :
293 0 : OGRSpatialReference* OGRGeomediaDataSource::GetGeomediaSRS(const char* pszGCoordSystemTable,
294 : const char* pszGCoordSystemGUID)
295 : {
296 0 : if (pszGCoordSystemTable == NULL || pszGCoordSystemGUID == NULL)
297 0 : return NULL;
298 :
299 0 : OGRLayer* poGCoordSystemTable = GetLayerByName(pszGCoordSystemTable);
300 0 : if (poGCoordSystemTable == NULL)
301 0 : return NULL;
302 :
303 0 : poGCoordSystemTable->ResetReading();
304 :
305 : OGRFeature* poFeature;
306 0 : while((poFeature = poGCoordSystemTable->GetNextFeature()) != NULL)
307 : {
308 0 : const char* pszCSGUID = poFeature->GetFieldAsString("CSGUID");
309 0 : if (pszCSGUID && strcmp(pszCSGUID, pszGCoordSystemGUID) == 0)
310 : {
311 0 : OGRSpatialReference* poSRS = OGRGetGeomediaSRS(poFeature);
312 0 : delete poFeature;
313 0 : return poSRS;
314 : }
315 :
316 0 : delete poFeature;
317 : }
318 :
319 0 : return NULL;
320 : }
321 :
322 : /************************************************************************/
323 : /* TestCapability() */
324 : /************************************************************************/
325 :
326 0 : int OGRGeomediaDataSource::TestCapability( const char * pszCap )
327 :
328 : {
329 0 : return FALSE;
330 : }
331 :
332 : /************************************************************************/
333 : /* GetLayer() */
334 : /************************************************************************/
335 :
336 0 : OGRLayer *OGRGeomediaDataSource::GetLayer( int iLayer )
337 :
338 : {
339 0 : if( iLayer < 0 || iLayer >= nLayers )
340 0 : return NULL;
341 : else
342 0 : return papoLayers[iLayer];
343 : }
344 :
345 :
346 : /************************************************************************/
347 : /* GetLayerByName() */
348 : /************************************************************************/
349 :
350 0 : OGRLayer *OGRGeomediaDataSource::GetLayerByName( const char* pszName )
351 :
352 : {
353 0 : if (pszName == NULL)
354 0 : return NULL;
355 0 : OGRLayer* poLayer = OGRDataSource::GetLayerByName(pszName);
356 0 : if (poLayer)
357 0 : return poLayer;
358 :
359 0 : for( int i = 0; i < nLayersWithInvisible; i++ )
360 : {
361 0 : poLayer = papoLayersInvisible[i];
362 :
363 0 : if( strcmp( pszName, poLayer->GetName() ) == 0 )
364 0 : return poLayer;
365 : }
366 :
367 : OGRGeomediaTableLayer *poGeomediaLayer;
368 :
369 0 : poGeomediaLayer = new OGRGeomediaTableLayer( this );
370 :
371 0 : if( poGeomediaLayer->Initialize(pszName, NULL, NULL) != CE_None )
372 : {
373 0 : delete poGeomediaLayer;
374 0 : return NULL;
375 : }
376 :
377 : papoLayersInvisible = (OGRGeomediaLayer**)CPLRealloc(papoLayersInvisible,
378 0 : (nLayersWithInvisible+1) * sizeof(OGRGeomediaLayer*));
379 0 : papoLayersInvisible[nLayersWithInvisible++] = poGeomediaLayer;
380 :
381 0 : return poGeomediaLayer;
382 : }
383 :
384 : /************************************************************************/
385 : /* ExecuteSQL() */
386 : /************************************************************************/
387 :
388 0 : OGRLayer * OGRGeomediaDataSource::ExecuteSQL( const char *pszSQLCommand,
389 : OGRGeometry *poSpatialFilter,
390 : const char *pszDialect )
391 :
392 : {
393 : /* -------------------------------------------------------------------- */
394 : /* Use generic imlplementation for OGRSQL dialect. */
395 : /* -------------------------------------------------------------------- */
396 0 : if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
397 : return OGRDataSource::ExecuteSQL( pszSQLCommand,
398 : poSpatialFilter,
399 0 : pszDialect );
400 :
401 : /* -------------------------------------------------------------------- */
402 : /* Execute statement. */
403 : /* -------------------------------------------------------------------- */
404 0 : CPLODBCStatement *poStmt = new CPLODBCStatement( &oSession );
405 :
406 0 : poStmt->Append( pszSQLCommand );
407 0 : if( !poStmt->ExecuteSQL() )
408 : {
409 : CPLError( CE_Failure, CPLE_AppDefined,
410 0 : "%s", oSession.GetLastError() );
411 0 : return NULL;
412 : }
413 :
414 : /* -------------------------------------------------------------------- */
415 : /* Are there result columns for this statement? */
416 : /* -------------------------------------------------------------------- */
417 0 : if( poStmt->GetColCount() == 0 )
418 : {
419 0 : delete poStmt;
420 0 : CPLErrorReset();
421 0 : return NULL;
422 : }
423 :
424 : /* -------------------------------------------------------------------- */
425 : /* Create a results layer. It will take ownership of the */
426 : /* statement. */
427 : /* -------------------------------------------------------------------- */
428 0 : OGRGeomediaSelectLayer *poLayer = NULL;
429 :
430 0 : poLayer = new OGRGeomediaSelectLayer( this, poStmt );
431 :
432 0 : if( poSpatialFilter != NULL )
433 0 : poLayer->SetSpatialFilter( poSpatialFilter );
434 :
435 0 : return poLayer;
436 : }
437 :
438 : /************************************************************************/
439 : /* ReleaseResultSet() */
440 : /************************************************************************/
441 :
442 0 : void OGRGeomediaDataSource::ReleaseResultSet( OGRLayer * poLayer )
443 :
444 : {
445 0 : delete poLayer;
446 0 : }
|