EVOLUTION-MANAGER
Edit File: ogrgeomediadatasource.cpp
/****************************************************************************** * $Id: ogrgeomediadatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $ * * Project: OpenGIS Simple Features Reference Implementation * Purpose: Implements OGRGeomediaDataSource class. * Author: Even Rouault, <even dot rouault at mines dash paris dot org> * ****************************************************************************** * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org> * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "ogr_geomedia.h" #include "ogrgeomediageometry.h" #include "cpl_conv.h" #include "cpl_string.h" #include <vector> CPL_CVSID("$Id: ogrgeomediadatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $"); /************************************************************************/ /* OGRGeomediaDataSource() */ /************************************************************************/ OGRGeomediaDataSource::OGRGeomediaDataSource() { pszName = NULL; papoLayers = NULL; papoLayersInvisible = NULL; nLayers = 0; nLayersWithInvisible = 0; } /************************************************************************/ /* ~OGRGeomediaDataSource() */ /************************************************************************/ OGRGeomediaDataSource::~OGRGeomediaDataSource() { int i; CPLFree( pszName ); for( i = 0; i < nLayers; i++ ) delete papoLayers[i]; CPLFree( papoLayers ); for( i = 0; i < nLayersWithInvisible; i++ ) delete papoLayersInvisible[i]; CPLFree( papoLayersInvisible ); } /************************************************************************/ /* CheckDSNStringTemplate() */ /* The string will be used as the formatting argument of sprintf with */ /* a string in vararg. So let's check there's only one '%s', and nothing*/ /* else */ /************************************************************************/ static int CheckDSNStringTemplate(const char* pszStr) { int nPercentSFound = FALSE; while(*pszStr) { if (*pszStr == '%') { if (pszStr[1] != 's') { return FALSE; } else { if (nPercentSFound) return FALSE; nPercentSFound = TRUE; } } pszStr ++; } return TRUE; } /************************************************************************/ /* Open() */ /************************************************************************/ int OGRGeomediaDataSource::Open( const char * pszNewName, int bUpdate, CPL_UNUSED int bTestOpen ) { CPLAssert( nLayers == 0 ); /* -------------------------------------------------------------------- */ /* If this is the name of an MDB file, then construct the */ /* appropriate connection string. Otherwise clip of GEOMEDIA: to */ /* get the DSN. */ /* */ /* -------------------------------------------------------------------- */ char *pszDSN; if( EQUALN(pszNewName,"GEOMEDIA:",9) ) pszDSN = CPLStrdup( pszNewName + 9 ); else { const char *pszDSNStringTemplate = NULL; pszDSNStringTemplate = CPLGetConfigOption( "GEOMEDIA_DRIVER_TEMPLATE", "DRIVER=Microsoft Access Driver (*.mdb);DBQ=%s"); if (!CheckDSNStringTemplate(pszDSNStringTemplate)) { CPLError( CE_Failure, CPLE_AppDefined, "Illegal value for GEOMEDIA_DRIVER_TEMPLATE option"); return FALSE; } pszDSN = (char *) CPLMalloc(strlen(pszNewName)+strlen(pszDSNStringTemplate)+100); sprintf( pszDSN, pszDSNStringTemplate, pszNewName ); } /* -------------------------------------------------------------------- */ /* Initialize based on the DSN. */ /* -------------------------------------------------------------------- */ CPLDebug( "Geomedia", "EstablishSession(%s)", pszDSN ); if( !oSession.EstablishSession( pszDSN, NULL, NULL ) ) { CPLError( CE_Failure, CPLE_AppDefined, "Unable to initialize ODBC connection to DSN for %s,\n" "%s", pszDSN, oSession.GetLastError() ); CPLFree( pszDSN ); return FALSE; } CPLFree( pszDSN ); pszName = CPLStrdup( pszNewName ); bDSUpdate = bUpdate; /* -------------------------------------------------------------------- */ /* Collect list of tables and their supporting info from */ /* GAliasTable. */ /* -------------------------------------------------------------------- */ CPLString osGFeaturesTable = GetTableNameFromType("INGRFeatures"); if (osGFeaturesTable.size() == 0) return FALSE; CPLString osGeometryProperties = GetTableNameFromType("INGRGeometryProperties"); CPLString osGCoordSystemTable = GetTableNameFromType("GCoordSystemTable"); std::vector<char **> apapszGeomColumns; { CPLODBCStatement oStmt( &oSession ); oStmt.Appendf( "SELECT FeatureName, PrimaryGeometryFieldName FROM %s", osGFeaturesTable.c_str() ); if( !oStmt.ExecuteSQL() ) { CPLDebug( "GEOMEDIA", "SELECT on %s fails, perhaps not a geomedia geodatabase?\n%s", osGFeaturesTable.c_str(), oSession.GetLastError() ); return FALSE; } while( oStmt.Fetch() ) { int i, iNew = apapszGeomColumns.size(); char **papszRecord = NULL; for( i = 0; i < 2; i++ ) papszRecord = CSLAddString( papszRecord, oStmt.GetColData(i) ); apapszGeomColumns.resize(iNew+1); apapszGeomColumns[iNew] = papszRecord; } } std::vector<OGRSpatialReference*> apoSRS; if (osGeometryProperties.size() != 0 && osGCoordSystemTable.size() != 0) { std::vector<CPLString> aosGUID; { CPLODBCStatement oStmt( &oSession ); oStmt.Appendf( "SELECT GCoordSystemGUID FROM %s", osGeometryProperties.c_str() ); if( !oStmt.ExecuteSQL() ) { CPLDebug( "GEOMEDIA", "SELECT on %s fails, perhaps not a geomedia geodatabase?\n%s", osGeometryProperties.c_str(), oSession.GetLastError() ); return FALSE; } while( oStmt.Fetch() ) { aosGUID.push_back(oStmt.GetColData(0)); } if (apapszGeomColumns.size() != aosGUID.size()) { CPLDebug( "GEOMEDIA", "%s and %s don't have the same size", osGFeaturesTable.c_str(), osGeometryProperties.c_str() ); return FALSE; } } int i; for(i=0; i<(int)aosGUID.size();i++) { apoSRS.push_back(GetGeomediaSRS(osGCoordSystemTable, aosGUID[i])); } } /* -------------------------------------------------------------------- */ /* Create a layer for each spatial table. */ /* -------------------------------------------------------------------- */ unsigned int iTable; papoLayers = (OGRGeomediaLayer **) CPLCalloc(apapszGeomColumns.size(), sizeof(void*)); for( iTable = 0; iTable < apapszGeomColumns.size(); iTable++ ) { char **papszRecord = apapszGeomColumns[iTable]; OGRGeomediaTableLayer *poLayer; poLayer = new OGRGeomediaTableLayer( this ); if( poLayer->Initialize( papszRecord[0], papszRecord[1], (apoSRS.size()) ? apoSRS[iTable] : NULL ) != CE_None ) { delete poLayer; } else { papoLayers[nLayers++] = poLayer; } CSLDestroy(papszRecord); } return TRUE; } /************************************************************************/ /* GetTableNameFromType() */ /************************************************************************/ CPLString OGRGeomediaDataSource::GetTableNameFromType(const char* pszTableType) { CPLODBCStatement oStmt( &oSession ); oStmt.Appendf( "SELECT TableName FROM GAliasTable WHERE TableType = '%s'", pszTableType ); if( !oStmt.ExecuteSQL() ) { CPLDebug( "GEOMEDIA", "SELECT for %s on GAliasTable fails, perhaps not a geomedia geodatabase?\n%s", pszTableType, oSession.GetLastError() ); return ""; } while( oStmt.Fetch() ) { return oStmt.GetColData(0); } return ""; } /************************************************************************/ /* GetGeomediaSRS() */ /************************************************************************/ OGRSpatialReference* OGRGeomediaDataSource::GetGeomediaSRS(const char* pszGCoordSystemTable, const char* pszGCoordSystemGUID) { if (pszGCoordSystemTable == NULL || pszGCoordSystemGUID == NULL) return NULL; OGRLayer* poGCoordSystemTable = GetLayerByName(pszGCoordSystemTable); if (poGCoordSystemTable == NULL) return NULL; poGCoordSystemTable->ResetReading(); OGRFeature* poFeature; while((poFeature = poGCoordSystemTable->GetNextFeature()) != NULL) { const char* pszCSGUID = poFeature->GetFieldAsString("CSGUID"); if (pszCSGUID && strcmp(pszCSGUID, pszGCoordSystemGUID) == 0) { OGRSpatialReference* poSRS = OGRGetGeomediaSRS(poFeature); delete poFeature; return poSRS; } delete poFeature; } return NULL; } /************************************************************************/ /* TestCapability() */ /************************************************************************/ int OGRGeomediaDataSource::TestCapability( CPL_UNUSED const char * pszCap ) { return FALSE; } /************************************************************************/ /* GetLayer() */ /************************************************************************/ OGRLayer *OGRGeomediaDataSource::GetLayer( int iLayer ) { if( iLayer < 0 || iLayer >= nLayers ) return NULL; else return papoLayers[iLayer]; } /************************************************************************/ /* GetLayerByName() */ /************************************************************************/ OGRLayer *OGRGeomediaDataSource::GetLayerByName( const char* pszName ) { if (pszName == NULL) return NULL; OGRLayer* poLayer = OGRDataSource::GetLayerByName(pszName); if (poLayer) return poLayer; for( int i = 0; i < nLayersWithInvisible; i++ ) { poLayer = papoLayersInvisible[i]; if( strcmp( pszName, poLayer->GetName() ) == 0 ) return poLayer; } OGRGeomediaTableLayer *poGeomediaLayer; poGeomediaLayer = new OGRGeomediaTableLayer( this ); if( poGeomediaLayer->Initialize(pszName, NULL, NULL) != CE_None ) { delete poGeomediaLayer; return NULL; } papoLayersInvisible = (OGRGeomediaLayer**)CPLRealloc(papoLayersInvisible, (nLayersWithInvisible+1) * sizeof(OGRGeomediaLayer*)); papoLayersInvisible[nLayersWithInvisible++] = poGeomediaLayer; return poGeomediaLayer; } /************************************************************************/ /* ExecuteSQL() */ /************************************************************************/ OGRLayer * OGRGeomediaDataSource::ExecuteSQL( const char *pszSQLCommand, OGRGeometry *poSpatialFilter, const char *pszDialect ) { /* -------------------------------------------------------------------- */ /* Use generic implementation for recognized dialects */ /* -------------------------------------------------------------------- */ if( IsGenericSQLDialect(pszDialect) ) return OGRDataSource::ExecuteSQL( pszSQLCommand, poSpatialFilter, pszDialect ); /* -------------------------------------------------------------------- */ /* Execute statement. */ /* -------------------------------------------------------------------- */ CPLODBCStatement *poStmt = new CPLODBCStatement( &oSession ); poStmt->Append( pszSQLCommand ); if( !poStmt->ExecuteSQL() ) { CPLError( CE_Failure, CPLE_AppDefined, "%s", oSession.GetLastError() ); return NULL; } /* -------------------------------------------------------------------- */ /* Are there result columns for this statement? */ /* -------------------------------------------------------------------- */ if( poStmt->GetColCount() == 0 ) { delete poStmt; CPLErrorReset(); return NULL; } /* -------------------------------------------------------------------- */ /* Create a results layer. It will take ownership of the */ /* statement. */ /* -------------------------------------------------------------------- */ OGRGeomediaSelectLayer *poLayer = NULL; poLayer = new OGRGeomediaSelectLayer( this, poStmt ); if( poSpatialFilter != NULL ) poLayer->SetSpatialFilter( poSpatialFilter ); return poLayer; } /************************************************************************/ /* ReleaseResultSet() */ /************************************************************************/ void OGRGeomediaDataSource::ReleaseResultSet( OGRLayer * poLayer ) { delete poLayer; }