LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/filegdb - FGdbDatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 148 117 79.1 %
Date: 2012-12-26 Functions: 26 15 57.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: FGdbDatasource.cpp 25025 2012-10-01 21:06:59Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements FileGDB OGR Datasource.
       6                 :  * Author:   Ragi Yaser Burhum, ragi@burhum.com
       7                 :  *           Paul Ramsey, pramsey at cleverelephant.ca
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2010, Ragi Yaser Burhum
      11                 :  * Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca>
      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 "ogr_fgdb.h"
      33                 : #include "cpl_conv.h"
      34                 : #include "cpl_string.h"
      35                 : #include "gdal.h"
      36                 : #include "FGdbUtils.h"
      37                 : 
      38                 : CPL_CVSID("$Id: FGdbDatasource.cpp 25025 2012-10-01 21:06:59Z rouault $");
      39                 : 
      40                 : using std::vector;
      41                 : using std::wstring;
      42                 : 
      43                 : /************************************************************************/
      44                 : /*                          FGdbDataSource()                           */
      45                 : /************************************************************************/
      46                 : 
      47              23 : FGdbDataSource::FGdbDataSource():
      48                 : OGRDataSource(),
      49              23 : m_pszName(0), m_pGeodatabase(NULL)
      50                 : {
      51              23 : }
      52                 : 
      53                 : /************************************************************************/
      54                 : /*                          ~FGdbDataSource()                          */
      55                 : /************************************************************************/
      56                 : 
      57              23 : FGdbDataSource::~FGdbDataSource()
      58                 : {   
      59              23 :     CPLFree( m_pszName );
      60                 : 
      61              23 :     size_t count = m_layers.size();
      62             203 :     for(size_t i = 0; i < count; ++i )
      63             180 :         delete m_layers[i];
      64                 : 
      65              23 :     if (m_pGeodatabase)
      66                 :     {
      67              23 :         ::CloseGeodatabase(*m_pGeodatabase);
      68              23 :         delete m_pGeodatabase;
      69                 :     }
      70              23 : }
      71                 : 
      72                 : 
      73                 : /************************************************************************/
      74                 : /*                                Open()                                */
      75                 : /************************************************************************/
      76                 : 
      77              23 : int FGdbDataSource::Open(Geodatabase* pGeodatabase, const char * pszNewName, int bUpdate )
      78                 : {
      79              23 :     m_pszName = CPLStrdup( pszNewName );
      80              23 :     m_pGeodatabase = pGeodatabase;
      81                 : 
      82              23 :     std::vector<std::wstring> typesRequested;
      83                 : 
      84                 :   // We're only interested in Tables, Feature Datasets and Feature Classes
      85              23 :   typesRequested.push_back(L"Feature Class");
      86              46 :   typesRequested.push_back(L"Table");
      87              46 :   typesRequested.push_back(L"Feature Dataset");
      88                 :   
      89              46 :     bool rv = LoadLayers(L"\\");
      90                 : 
      91              23 :     return rv;
      92                 : }
      93                 : 
      94                 : /************************************************************************/
      95                 : /*                          OpenFGDBTables()                            */
      96                 : /************************************************************************/
      97                 : 
      98              24 : bool FGdbDataSource::OpenFGDBTables(const std::wstring &type,
      99                 :                                     const std::vector<std::wstring> &layers)
     100                 : {
     101                 :     fgdbError hr;
     102             171 :     for ( unsigned int i = 0; i < layers.size(); i++ )
     103                 :     {
     104             147 :         Table* pTable = new Table;
     105                 :         //CPLDebug("FGDB", "Opening %s", WStringToString(layers[i]).c_str());
     106             147 :         if (FAILED(hr = m_pGeodatabase->OpenTable(layers[i], *pTable)))
     107                 :         {
     108               0 :             delete pTable;
     109               0 :             GDBDebug(hr, "Error opening " + WStringToString(layers[i]) + ". Skipping it");
     110               0 :             continue;
     111                 :         }
     112             147 :         FGdbLayer* pLayer = new FGdbLayer;
     113             294 :         if (!pLayer->Initialize(this, pTable, layers[i], type))
     114                 :         {
     115               0 :             delete pLayer;
     116               0 :             return GDBErr(hr, "Error initializing OGRLayer for " + WStringToString(layers[i]));
     117                 :         }
     118                 : 
     119             147 :         m_layers.push_back(pLayer);
     120                 :     }
     121              24 :     return true;
     122                 : }
     123                 : 
     124                 : /************************************************************************/
     125                 : /*                            LoadLayers()                             */
     126                 : /************************************************************************/
     127                 : 
     128              23 : bool FGdbDataSource::LoadLayers(const std::wstring &root) 
     129                 : {
     130              23 :     std::vector<wstring> tables;
     131              23 :     std::vector<wstring> featureclasses;
     132              23 :     std::vector<wstring> featuredatasets;
     133                 :     fgdbError hr;
     134                 : 
     135                 :     /* Find all the Tables in the root */
     136              23 :     if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Table", tables)) )
     137                 :     {
     138               0 :         return GDBErr(hr, "Error reading Tables in " + WStringToString(root));
     139                 :     }
     140                 :     /* Open the tables we found */
     141              23 :     if ( tables.size() > 0 && ! OpenFGDBTables(L"Table", tables) )
     142               0 :         return false;
     143                 : 
     144                 :     /* Find all the Feature Classes in the root */
     145              23 :     if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Feature Class", featureclasses)) )
     146                 :     {
     147               0 :         return GDBErr(hr, "Error reading Feature Classes in " + WStringToString(root));
     148                 :     }
     149                 :     /* Open the tables we found */
     150              23 :     if ( featureclasses.size() > 0 && ! OpenFGDBTables(L"Feature Class", featureclasses) )
     151               0 :         return false;
     152                 : 
     153                 :     /* Find all the Feature Datasets in the root */
     154              23 :     if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Feature Dataset", featuredatasets)) )
     155                 :     {
     156               0 :         return GDBErr(hr, "Error reading Feature Datasets in " + WStringToString(root));
     157                 :     }
     158                 :     /* Look for Feature Classes inside the Feature Dataset */
     159              24 :     for ( unsigned int i = 0; i < featuredatasets.size(); i++ )
     160                 :     {
     161               1 :         if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(featuredatasets[i], L"Feature Class", featureclasses)) )
     162                 :         {
     163               0 :             return GDBErr(hr, "Error reading Feature Classes in " + WStringToString(featuredatasets[i]));
     164                 :         }
     165               1 :         if ( featureclasses.size() > 0 && ! OpenFGDBTables(L"Feature Class", featureclasses) )
     166               0 :             return false;
     167                 :     }
     168              23 :     return true;
     169                 : }
     170                 : 
     171                 : 
     172                 : #if 0
     173                 : /************************************************************************/
     174                 : /*                            LoadLayersOld()                              */
     175                 : /************************************************************************/
     176                 : 
     177                 : /* Old recursive LoadLayers. Removed in favor of simple one that only
     178                 :    looks at FeatureClasses and Tables. */
     179                 : 
     180                 : // Flattens out hierarchichal GDB structure
     181                 : bool FGdbDataSource::LoadLayersOld(const std::vector<wstring> & datasetTypes,
     182                 :                                 const wstring & parent)
     183                 : {
     184                 :     long hr = S_OK;
     185                 : 
     186                 :     // I didn't find an API to give me the type of the dataset based on name - I am *not*
     187                 :     // parsing XML for something like this - in the meantime I can use this hack to see
     188                 :     // if the dataset had any children whatsoever - if so, then I won't attempt to open it
     189                 :     // otherwise, do attempt to do that
     190                 : 
     191                 :     bool childrenFound = false;
     192                 :     bool errorsEncountered = false;
     193                 : 
     194                 :     for (size_t dsTypeIndex = 0; dsTypeIndex < datasetTypes.size(); dsTypeIndex++)
     195                 :     {
     196                 :         std::vector<wstring> childDatasets;
     197                 :         m_pGeodatabase->GetChildDatasets( parent, datasetTypes[dsTypeIndex], childDatasets);
     198                 : 
     199                 :         if (childDatasets.size() > 0)
     200                 :         {
     201                 :             //it is a container of other datasets
     202                 : 
     203                 :             for (size_t childDatasetIndex = 0;
     204                 :                  childDatasetIndex < childDatasets.size();
     205                 :                  childDatasetIndex++)
     206                 :             {
     207                 :                 childrenFound = true;
     208                 : 
     209                 :                 // do something with it
     210                 :                 // For now, we just ignore dataset containers and only open the children
     211                 :                 //std::wcout << datasetTypes[dsTypeIndex] << L" " << childDatasets[childDatasetIndex] << std::endl;
     212                 : 
     213                 :                 if (!LoadLayersOld(datasetTypes, childDatasets[childDatasetIndex]))
     214                 :                     errorsEncountered = true;
     215                 :             }
     216                 :         }
     217                 :     }
     218                 : 
     219                 :     //it is a full fledged dataset itself without children - open it (except the root)
     220                 : 
     221                 :     if ((!childrenFound) && parent != L"\\")
     222                 :     {
     223                 :         //wcout << "Opening " << parent << "...";
     224                 :         Table* pTable = new Table;
     225                 :         if (FAILED(hr = m_pGeodatabase->OpenTable(parent,*pTable)))
     226                 :         {
     227                 :             delete pTable;
     228                 :             return GDBErr(hr, "Error opening " + WStringToString(parent));
     229                 :         }
     230                 : 
     231                 :         FGdbLayer* pLayer = new FGdbLayer;
     232                 : 
     233                 :         //pLayer has ownership of the table pointer as soon Initialize is called
     234                 :         if (!pLayer->Initialize(this, pTable, parent))
     235                 :         {
     236                 :             delete pLayer;
     237                 : 
     238                 :             return GDBErr(hr, "Error initializing OGRLayer for " +
     239                 :                           WStringToString(parent));
     240                 :         }
     241                 : 
     242                 :         m_layers.push_back(pLayer);
     243                 :     }
     244                 : 
     245                 :     return !errorsEncountered;
     246                 : }
     247                 : #endif
     248                 : 
     249                 : 
     250                 : /************************************************************************/
     251                 : /*                            DeleteLayer()                             */
     252                 : /************************************************************************/
     253                 : 
     254               2 : OGRErr FGdbDataSource::DeleteLayer( int iLayer )
     255                 : {
     256               2 :     if( iLayer < 0 || iLayer >= static_cast<int>(m_layers.size()) )
     257               0 :         return OGRERR_FAILURE;
     258                 : 
     259                 :     // Fetch FGDBAPI Table before deleting OGR layer object
     260                 : 
     261               2 :     Table* pTable = m_layers[iLayer]->GetTable();
     262                 : 
     263               2 :     std::string name = m_layers[iLayer]->GetLayerDefn()->GetName();
     264               4 :     std::wstring strPath = m_layers[iLayer]->GetTablePath();
     265               2 :     std::wstring strType = m_layers[iLayer]->GetType();
     266                 : 
     267                 :     // delete OGR layer
     268               2 :     delete m_layers[iLayer];
     269                 : 
     270               2 :     pTable = NULL; // OGR Layer had ownership of FGDB Table
     271                 : 
     272               2 :     m_layers.erase(m_layers.begin() + iLayer);
     273                 : 
     274                 :     long hr;
     275                 :   
     276               2 :     if (FAILED(hr = m_pGeodatabase->Delete(strPath, strType)))
     277                 :     {
     278                 :         CPLError( CE_Warning, CPLE_AppDefined,
     279               0 :                  "%s was not deleted however it has been closed", name.c_str());
     280               0 :         GDBErr(hr, "Failed deleting dataset");
     281               0 :         return OGRERR_FAILURE;
     282                 :     }
     283                 : 
     284               2 :     return OGRERR_NONE;
     285                 : }
     286                 : 
     287                 : /************************************************************************/
     288                 : /*                           TestCapability()                           */
     289                 : /************************************************************************/
     290                 : 
     291               3 : int FGdbDataSource::TestCapability( const char * pszCap )
     292                 : {
     293               3 :     if( EQUAL(pszCap,ODsCCreateLayer) )
     294               1 :         return TRUE;
     295                 : 
     296               2 :     else if( EQUAL(pszCap,ODsCDeleteLayer) )
     297               0 :         return TRUE;
     298                 : 
     299               2 :     return FALSE;
     300                 : }
     301                 : 
     302                 : 
     303                 : /************************************************************************/
     304                 : /*                              GetLayer()                              */
     305                 : /************************************************************************/
     306                 : 
     307            2005 : OGRLayer *FGdbDataSource::GetLayer( int iLayer )
     308                 : { 
     309            2005 :     int count = static_cast<int>(m_layers.size());
     310                 : 
     311            2005 :     if( iLayer < 0 || iLayer >= count )
     312               4 :         return NULL;
     313                 :     else
     314            2001 :         return m_layers[iLayer];
     315                 : }
     316                 : 
     317                 : /************************************************************************/
     318                 : /*                              CreateLayer()                           */
     319                 : /*                                                                      */
     320                 : /* See FGdbLayer::Create for creation options                           */
     321                 : /************************************************************************/
     322                 : 
     323                 : OGRLayer *
     324              38 : FGdbDataSource::CreateLayer( const char * pszLayerName,
     325                 :                               OGRSpatialReference *poSRS,
     326                 :                               OGRwkbGeometryType eType,
     327                 :                               char ** papszOptions )
     328                 : {
     329              38 :     FGdbLayer* pLayer = new FGdbLayer;
     330              38 :     if (!pLayer->Create(this, pszLayerName, poSRS, eType, papszOptions))
     331                 :     {
     332               3 :         delete pLayer;
     333               3 :         return NULL;
     334                 :     }
     335                 : 
     336              35 :     m_layers.push_back(pLayer);
     337                 : 
     338              35 :     return pLayer;  
     339                 : }
     340                 : 
     341                 : 
     342                 : /************************************************************************/
     343                 : /*                   OGRFGdbSingleFeatureLayer                          */
     344                 : /************************************************************************/
     345                 : 
     346                 : class OGRFGdbSingleFeatureLayer : public OGRLayer
     347                 : {
     348                 :   private:
     349                 :     char               *pszVal;
     350                 :     OGRFeatureDefn     *poFeatureDefn;
     351                 :     int                 iNextShapeId;
     352                 : 
     353                 :   public:
     354                 :                         OGRFGdbSingleFeatureLayer( const char* pszLayerName,
     355                 :                                                    const char *pszVal );
     356                 :                         ~OGRFGdbSingleFeatureLayer();
     357                 : 
     358               0 :     virtual void        ResetReading() { iNextShapeId = 0; }
     359                 :     virtual OGRFeature *GetNextFeature();
     360               0 :     virtual OGRFeatureDefn *GetLayerDefn() { return poFeatureDefn; }
     361               0 :     virtual int         TestCapability( const char * ) { return FALSE; }
     362                 : };
     363                 : 
     364                 : /************************************************************************/
     365                 : /*                    OGRFGdbSingleFeatureLayer()                       */
     366                 : /************************************************************************/
     367                 : 
     368              30 : OGRFGdbSingleFeatureLayer::OGRFGdbSingleFeatureLayer(const char* pszLayerName,
     369              30 :                                                      const char *pszVal )
     370                 : {
     371              30 :     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
     372              30 :     poFeatureDefn->Reference();
     373              30 :     OGRFieldDefn oField( "FIELD_1", OFTString );
     374              30 :     poFeatureDefn->AddFieldDefn( &oField );
     375                 : 
     376              30 :     iNextShapeId = 0;
     377              30 :     this->pszVal = pszVal ? CPLStrdup(pszVal) : NULL;
     378              30 : }
     379                 : 
     380                 : /************************************************************************/
     381                 : /*                   ~OGRFGdbSingleFeatureLayer()                       */
     382                 : /************************************************************************/
     383                 : 
     384              30 : OGRFGdbSingleFeatureLayer::~OGRFGdbSingleFeatureLayer()
     385                 : {
     386              30 :     if( poFeatureDefn != NULL )
     387              30 :         poFeatureDefn->Release();
     388              30 :     CPLFree(pszVal);
     389              30 : }
     390                 : 
     391                 : 
     392                 : /************************************************************************/
     393                 : /*                           GetNextFeature()                           */
     394                 : /************************************************************************/
     395                 : 
     396               0 : OGRFeature * OGRFGdbSingleFeatureLayer::GetNextFeature()
     397                 : {
     398               0 :     if (iNextShapeId != 0)
     399               0 :         return NULL;
     400                 : 
     401               0 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
     402               0 :     if (pszVal)
     403               0 :         poFeature->SetField(0, pszVal);
     404               0 :     poFeature->SetFID(iNextShapeId ++);
     405               0 :     return poFeature;
     406                 : }
     407                 : 
     408                 : /************************************************************************/
     409                 : /*                              ExecuteSQL()                            */
     410                 : /************************************************************************/
     411                 : 
     412              66 : OGRLayer * FGdbDataSource::ExecuteSQL( const char *pszSQLCommand,
     413                 :                                        OGRGeometry *poSpatialFilter,
     414                 :                                        const char *pszDialect )
     415                 : 
     416                 : {
     417              66 :     if ( pszDialect != NULL && EQUAL(pszDialect, "OGRSQL") )
     418                 :         return OGRDataSource::ExecuteSQL( pszSQLCommand,
     419                 :                                           poSpatialFilter,
     420               0 :                                           pszDialect );
     421                 : 
     422                 : /* -------------------------------------------------------------------- */
     423                 : /*      Special case GetLayerDefinition                                 */
     424                 : /* -------------------------------------------------------------------- */
     425              66 :     if (EQUALN(pszSQLCommand, "GetLayerDefinition ", strlen("GetLayerDefinition ")))
     426                 :     {
     427              15 :         FGdbLayer* poLayer = (FGdbLayer*) GetLayerByName(pszSQLCommand + strlen("GetLayerDefinition "));
     428              15 :         if (poLayer)
     429                 :         {
     430              15 :             char* pszVal = NULL;
     431              15 :             poLayer->GetLayerXML(&pszVal);
     432              15 :             OGRLayer* poRet = new OGRFGdbSingleFeatureLayer( "LayerDefinition", pszVal );
     433              15 :             CPLFree(pszVal);
     434              15 :             return poRet;
     435                 :         }
     436                 :         else
     437               0 :             return NULL;
     438                 :     }
     439                 : 
     440                 : /* -------------------------------------------------------------------- */
     441                 : /*      Special case GetLayerMetadata                                   */
     442                 : /* -------------------------------------------------------------------- */
     443              51 :     if (EQUALN(pszSQLCommand, "GetLayerMetadata ", strlen("GetLayerMetadata ")))
     444                 :     {
     445              15 :         FGdbLayer* poLayer = (FGdbLayer*) GetLayerByName(pszSQLCommand + strlen("GetLayerMetadata "));
     446              15 :         if (poLayer)
     447                 :         {
     448              15 :             char* pszVal = NULL;
     449              15 :             poLayer->GetLayerMetadataXML(&pszVal);
     450              15 :             OGRLayer* poRet = new OGRFGdbSingleFeatureLayer( "LayerMetadata", pszVal );
     451              15 :             CPLFree(pszVal);
     452              15 :             return poRet;
     453                 :         }
     454                 :         else
     455               0 :             return NULL;
     456                 :     }
     457                 : 
     458                 :     /* TODO: remove that workaround when the SDK has finally a decent */
     459                 :     /* SQL support ! */
     460              36 :     if( EQUALN(pszSQLCommand, "SELECT ", 7) && pszDialect == NULL )
     461                 :     {
     462                 :         CPLDebug("FGDB", "Support for SELECT is known to be partially "
     463                 :                          "non-compliant with FileGDB SDK API v1.2.\n"
     464                 :                          "So for now, we use default OGR SQL engine. "
     465                 :                          "Explicitely specify -dialect FileGDB\n"
     466              32 :                          "to use the SQL engine from the FileGDB SDK API");
     467                 :         return OGRDataSource::ExecuteSQL( pszSQLCommand,
     468                 :                                         poSpatialFilter,
     469              32 :                                         pszDialect );
     470                 :     }
     471                 : 
     472                 : /* -------------------------------------------------------------------- */
     473                 : /*      Run the SQL                                                     */
     474                 : /* -------------------------------------------------------------------- */
     475               4 :     EnumRows* pEnumRows = new EnumRows;
     476                 :     long hr;
     477               8 :     if (FAILED(hr = m_pGeodatabase->ExecuteSQL(
     478                 :                                 StringToWString(pszSQLCommand), true, *pEnumRows)))
     479                 :     {
     480               2 :         GDBErr(hr, CPLSPrintf("Failed at executing '%s'", pszSQLCommand));
     481               4 :         delete pEnumRows;
     482               2 :         return NULL;
     483                 :     }
     484                 : 
     485               2 :     if( EQUALN(pszSQLCommand, "SELECT ", 7) )
     486                 :     {
     487               1 :         return new FGdbResultLayer(this, pszSQLCommand, pEnumRows);
     488                 :     }
     489                 :     else
     490                 :     {
     491               1 :         delete pEnumRows;
     492               1 :         return NULL;
     493                 :     }
     494                 : }
     495                 : 
     496                 : /************************************************************************/
     497                 : /*                           ReleaseResultSet()                         */
     498                 : /************************************************************************/
     499                 : 
     500              63 : void FGdbDataSource::ReleaseResultSet( OGRLayer * poResultsSet )
     501                 : {
     502              63 :     delete poResultsSet;
     503            2202 : }

Generated by: LCOV version 1.7