LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/filegdb - FGdbDatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 246 294 83.7 %
Date: 2025-02-18 14:19:29 Functions: 23 27 85.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements FileGDB OGR Datasource.
       5             :  * Author:   Ragi Yaser Burhum, ragi@burhum.com
       6             :  *           Paul Ramsey, pramsey at cleverelephant.ca
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2010, Ragi Yaser Burhum
      10             :  * Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca>
      11             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ****************************************************************************/
      15             : 
      16             : #include "ogr_fgdb.h"
      17             : #include "cpl_conv.h"
      18             : #include "cpl_string.h"
      19             : #include "gdal.h"
      20             : #include "FGdbUtils.h"
      21             : #include "cpl_multiproc.h"
      22             : 
      23             : #include "filegdb_fielddomain.h"
      24             : #include "filegdb_relationship.h"
      25             : 
      26             : using std::vector;
      27             : using std::wstring;
      28             : 
      29             : /***********************************************************************/
      30             : /*                         OGRFileGDBGroup                             */
      31             : /***********************************************************************/
      32             : 
      33             : class OGRFileGDBGroup final : public GDALGroup
      34             : {
      35             :   protected:
      36             :     friend class FGdbDataSource;
      37             :     std::vector<std::shared_ptr<GDALGroup>> m_apoSubGroups{};
      38             :     std::vector<OGRLayer *> m_apoLayers{};
      39             : 
      40             :   public:
      41          41 :     OGRFileGDBGroup(const std::string &osParentName, const char *pszName)
      42          41 :         : GDALGroup(osParentName, pszName)
      43             :     {
      44          41 :     }
      45             : 
      46             :     std::vector<std::string>
      47             :     GetGroupNames(CSLConstList papszOptions) const override;
      48             :     std::shared_ptr<GDALGroup>
      49             :     OpenGroup(const std::string &osName,
      50             :               CSLConstList papszOptions) const override;
      51             : 
      52             :     std::vector<std::string>
      53             :     GetVectorLayerNames(CSLConstList papszOptions) const override;
      54             :     OGRLayer *OpenVectorLayer(const std::string &osName,
      55             :                               CSLConstList papszOptions) const override;
      56             : };
      57             : 
      58           2 : std::vector<std::string> OGRFileGDBGroup::GetGroupNames(CSLConstList) const
      59             : {
      60           2 :     std::vector<std::string> ret;
      61           4 :     for (const auto &poSubGroup : m_apoSubGroups)
      62           2 :         ret.emplace_back(poSubGroup->GetName());
      63           2 :     return ret;
      64             : }
      65             : 
      66           3 : std::shared_ptr<GDALGroup> OGRFileGDBGroup::OpenGroup(const std::string &osName,
      67             :                                                       CSLConstList) const
      68             : {
      69           6 :     for (const auto &poSubGroup : m_apoSubGroups)
      70             :     {
      71           5 :         if (poSubGroup->GetName() == osName)
      72           2 :             return poSubGroup;
      73             :     }
      74           1 :     return nullptr;
      75             : }
      76             : 
      77             : std::vector<std::string>
      78           3 : OGRFileGDBGroup::GetVectorLayerNames(CSLConstList) const
      79             : {
      80           3 :     std::vector<std::string> ret;
      81           7 :     for (const auto &poLayer : m_apoLayers)
      82           4 :         ret.emplace_back(poLayer->GetName());
      83           3 :     return ret;
      84             : }
      85             : 
      86           5 : OGRLayer *OGRFileGDBGroup::OpenVectorLayer(const std::string &osName,
      87             :                                            CSLConstList) const
      88             : {
      89           8 :     for (const auto &poLayer : m_apoLayers)
      90             :     {
      91           7 :         if (poLayer->GetName() == osName)
      92           4 :             return poLayer;
      93             :     }
      94           1 :     return nullptr;
      95             : }
      96             : 
      97             : /************************************************************************/
      98             : /*                          FGdbDataSource()                           */
      99             : /************************************************************************/
     100             : 
     101          36 : FGdbDataSource::FGdbDataSource(bool bUseDriverMutex,
     102             :                                FGdbDatabaseConnection *pConnection,
     103          36 :                                bool bUseOpenFileGDB)
     104             :     : m_bUseDriverMutex(bUseDriverMutex), m_pConnection(pConnection),
     105             :       m_pGeodatabase(nullptr), m_poOpenFileGDBDrv(nullptr),
     106          36 :       m_bUseOpenFileGDB(bUseOpenFileGDB)
     107             : {
     108          36 :     SetDescription(pConnection->m_osName.c_str());
     109          36 :     poDriver = GDALDriver::FromHandle(GDALGetDriverByName("FileGDB"));
     110          36 : }
     111             : 
     112             : /************************************************************************/
     113             : /*                          ~FGdbDataSource()                          */
     114             : /************************************************************************/
     115             : 
     116          72 : FGdbDataSource::~FGdbDataSource()
     117             : {
     118          72 :     CPLMutexHolderOptionalLockD(m_bUseDriverMutex ? FGdbDriver::hMutex
     119             :                                                   : nullptr);
     120             : 
     121             :     // CloseInternal();
     122          36 :     size_t count = m_layers.size();
     123         173 :     for (size_t i = 0; i < count; ++i)
     124             :     {
     125         137 :         if (FGdbLayer *poFgdbLayer = dynamic_cast<FGdbLayer *>(m_layers[i]))
     126             :         {
     127         132 :             poFgdbLayer->CloseGDBObjects();
     128             :         }
     129             :     }
     130             : 
     131          36 :     if (m_bUseDriverMutex)
     132          36 :         FGdbDriver::Release(m_osPublicName);
     133             : 
     134             :     // size_t count = m_layers.size();
     135         173 :     for (size_t i = 0; i < count; ++i)
     136             :     {
     137             :         // only delete layers coming from this driver -- the tables opened by
     138             :         // the OpenFileGDB driver will be deleted when we close the OpenFileGDB
     139             :         // datasource
     140         137 :         if (FGdbLayer *poFgdbLayer = dynamic_cast<FGdbLayer *>(m_layers[i]))
     141             :         {
     142         132 :             delete poFgdbLayer;
     143             :         }
     144             :     }
     145          72 : }
     146             : 
     147             : /************************************************************************/
     148             : /*                                Open()                                */
     149             : /************************************************************************/
     150             : 
     151          36 : int FGdbDataSource::Open(const char *pszNewName, int /* bUpdate */,
     152             :                          const char *pszPublicName)
     153             : {
     154          36 :     m_osFSName = pszNewName;
     155          36 :     m_osPublicName = (pszPublicName) ? pszPublicName : pszNewName;
     156          36 :     m_pGeodatabase = m_pConnection->GetGDB();
     157          36 :     m_poOpenFileGDBDrv = (GDALDriver *)GDALGetDriverByName("OpenFileGDB");
     158             : 
     159          36 :     return LoadLayers(L"\\");
     160             : }
     161             : 
     162             : /************************************************************************/
     163             : /*                           CloseInternal()                            */
     164             : /************************************************************************/
     165             : 
     166           0 : int FGdbDataSource::CloseInternal(int bCloseGeodatabase)
     167             : {
     168           0 :     size_t count = m_layers.size();
     169           0 :     for (size_t i = 0; i < count; ++i)
     170             :     {
     171           0 :         if (FGdbLayer *poFgdbLayer = dynamic_cast<FGdbLayer *>(m_layers[i]))
     172             :         {
     173           0 :             poFgdbLayer->CloseGDBObjects();
     174             :         }
     175             :     }
     176             : 
     177           0 :     if (m_pConnection && bCloseGeodatabase)
     178           0 :         m_pConnection->CloseGeodatabase();
     179           0 :     m_pGeodatabase = nullptr;
     180           0 :     return true;
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                          OpenFGDBTables()                            */
     185             : /************************************************************************/
     186             : 
     187          44 : bool FGdbDataSource::OpenFGDBTables(OGRFileGDBGroup *group,
     188             :                                     const std::wstring &type,
     189             :                                     const std::vector<std::wstring> &layers)
     190             : {
     191             : #ifdef DISPLAY_RELATED_DATASETS
     192             :     std::vector<std::wstring> relationshipTypes;
     193             :     m_pGeodatabase->GetDatasetRelationshipTypes(relationshipTypes);
     194             :     std::vector<std::wstring> datasetTypes;
     195             :     m_pGeodatabase->GetDatasetTypes(datasetTypes);
     196             : #endif
     197             : 
     198             :     fgdbError hr;
     199         177 :     for (unsigned int i = 0; i < layers.size(); i++)
     200             :     {
     201         133 :         Table *pTable = new Table;
     202             :         // CPLDebug("FGDB", "Opening %s", WStringToString(layers[i]).c_str());
     203         133 :         if (FAILED(hr = m_pGeodatabase->OpenTable(layers[i], *pTable)))
     204             :         {
     205           1 :             delete pTable;
     206             : 
     207           2 :             std::wstring fgdb_error_desc_w;
     208             :             fgdbError er;
     209           1 :             er = FileGDBAPI::ErrorInfo::GetErrorDescription(hr,
     210             :                                                             fgdb_error_desc_w);
     211           1 :             const char *pszLikelyReason =
     212             :                 "Might be due to unsupported spatial reference system. Using "
     213             :                 "OpenFileGDB driver or FileGDB SDK >= 1.4 should solve it";
     214           1 :             if (er == S_OK)
     215             :             {
     216             :                 std::string fgdb_error_desc =
     217           2 :                     WStringToString(fgdb_error_desc_w);
     218           1 :                 if (fgdb_error_desc == "FileGDB compression is not installed.")
     219             :                 {
     220           0 :                     pszLikelyReason = "Using FileGDB SDK 1.4 or later should "
     221             :                                       "solve this issue.";
     222             :                 }
     223             :             }
     224             : 
     225           1 :             GDBErr(hr, "Error opening " + WStringToString(layers[i]),
     226             :                    CE_Warning,
     227           2 :                    (". Skipping it. " + CPLString(pszLikelyReason)).c_str());
     228           1 :             continue;
     229             :         }
     230             : 
     231             : #ifdef DISPLAY_RELATED_DATASETS
     232             :         CPLDebug("FGDB", "Finding datasets related to %s",
     233             :                  WStringToString(layers[i]).c_str());
     234             :         // Slow !
     235             :         for (const auto &relType : relationshipTypes)
     236             :         {
     237             :             for (const auto &itemType : datasetTypes)
     238             :             {
     239             :                 std::vector<std::wstring> relatedDatasets;
     240             :                 m_pGeodatabase->GetRelatedDatasets(layers[i], relType, itemType,
     241             :                                                    relatedDatasets);
     242             : 
     243             :                 std::vector<std::string> relatedDatasetDefs;
     244             :                 m_pGeodatabase->GetRelatedDatasetDefinitions(
     245             :                     layers[i], relType, itemType, relatedDatasetDefs);
     246             : 
     247             :                 if (!relatedDatasets.empty() || !relatedDatasetDefs.empty())
     248             :                 {
     249             :                     CPLDebug("FGDB", "relationshipType: %s",
     250             :                              WStringToString(relType).c_str());
     251             :                     CPLDebug("FGDB", "itemType: %s",
     252             :                              WStringToString(itemType).c_str());
     253             :                 }
     254             :                 for (const auto &name : relatedDatasets)
     255             :                 {
     256             :                     CPLDebug("FGDB", "Related dataset: %s",
     257             :                              WStringToString(name).c_str());
     258             :                 }
     259             :                 for (const auto &xml : relatedDatasetDefs)
     260             :                 {
     261             :                     CPLDebug("FGDB", "Related dataset def: %s", xml.c_str());
     262             :                 }
     263             :             }
     264             :         }
     265             : #endif
     266             : 
     267         132 :         FGdbLayer *pLayer = new FGdbLayer();
     268         132 :         if (!pLayer->Initialize(this, pTable, layers[i], type))
     269             :         {
     270           0 :             delete pLayer;
     271           0 :             return GDBErr(hr, "Error initializing OGRLayer for " +
     272           0 :                                   WStringToString(layers[i]));
     273             :         }
     274             : 
     275         132 :         m_layers.push_back(pLayer);
     276         132 :         group->m_apoLayers.emplace_back(pLayer);
     277             :     }
     278          44 :     return true;
     279             : }
     280             : 
     281             : /************************************************************************/
     282             : /*                            LoadLayers()                             */
     283             : /************************************************************************/
     284             : 
     285          36 : bool FGdbDataSource::LoadLayers(const std::wstring &root)
     286             : {
     287          72 :     std::vector<wstring> tables;
     288          72 :     std::vector<wstring> featureclasses;
     289          72 :     std::vector<wstring> featuredatasets;
     290             :     fgdbError hr;
     291             : 
     292          72 :     auto poRootGroup = std::make_shared<OGRFileGDBGroup>(std::string(), "");
     293          36 :     m_poRootGroup = poRootGroup;
     294             : 
     295             :     /* Find all the Tables in the root */
     296          36 :     if (FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Table", tables)))
     297             :     {
     298           0 :         return GDBErr(hr, "Error reading Tables in " + WStringToString(root));
     299             :     }
     300             :     /* Open the tables we found */
     301          36 :     if (!tables.empty() && !OpenFGDBTables(poRootGroup.get(), L"Table", tables))
     302           0 :         return false;
     303             : 
     304             :     /* Find all the Feature Classes in the root */
     305          36 :     if (FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Feature Class",
     306             :                                                      featureclasses)))
     307             :     {
     308           0 :         return GDBErr(hr, "Error reading Feature Classes in " +
     309           0 :                               WStringToString(root));
     310             :     }
     311             :     /* Open the tables we found */
     312          69 :     if (!featureclasses.empty() &&
     313          69 :         !OpenFGDBTables(poRootGroup.get(), L"Feature Class", featureclasses))
     314           0 :         return false;
     315             : 
     316             :     /* Find all the Feature Datasets in the root */
     317          36 :     if (FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Feature Dataset",
     318             :                                                      featuredatasets)))
     319             :     {
     320           0 :         return GDBErr(hr, "Error reading Feature Datasets in " +
     321           0 :                               WStringToString(root));
     322             :     }
     323             :     /* Look for Feature Classes inside the Feature Dataset */
     324          41 :     for (unsigned int i = 0; i < featuredatasets.size(); i++)
     325             :     {
     326             :         const std::string featureDatasetPath(
     327           5 :             WStringToString(featuredatasets[i]));
     328           5 :         if (FAILED(hr = m_pGeodatabase->GetChildDatasets(
     329             :                        featuredatasets[i], L"Feature Class", featureclasses)))
     330             :         {
     331           0 :             return GDBErr(hr, "Error reading Feature Classes in " +
     332           0 :                                   featureDatasetPath);
     333             :         }
     334           5 :         std::string featureDatasetName(featureDatasetPath);
     335           5 :         if (!featureDatasetName.empty() && featureDatasetPath[0] == '\\')
     336           5 :             featureDatasetName = featureDatasetName.substr(1);
     337             :         auto poFeatureDatasetGroup = std::make_shared<OGRFileGDBGroup>(
     338           5 :             poRootGroup->GetName(), featureDatasetName.c_str());
     339           5 :         poRootGroup->m_apoSubGroups.emplace_back(poFeatureDatasetGroup);
     340          10 :         if (!featureclasses.empty() &&
     341          10 :             !OpenFGDBTables(poFeatureDatasetGroup.get(), L"Feature Class",
     342             :                             featureclasses))
     343           0 :             return false;
     344             :     }
     345             : 
     346             :     // Look for items which aren't present in the GDB_Items table (see
     347             :     // https://github.com/OSGeo/gdal/issues/4463) We do this by browsing the
     348             :     // catalog table (using the OpenFileGDB driver) and looking for items we
     349             :     // haven't yet found. If we find any, we have no choice but to load these
     350             :     // using the OpenFileGDB driver, as the ESRI SDK refuses to acknowledge that
     351             :     // they exist (despite ArcGIS itself showing them!)
     352          36 :     int iGDBItems = -1;
     353          36 :     const char *const apszDrivers[2] = {"OpenFileGDB", nullptr};
     354             :     const std::string osSystemCatalog =
     355          72 :         CPLFormFilenameSafe(m_osFSName, "a00000001", "gdbtable");
     356          36 :     if (m_bUseOpenFileGDB)
     357             :     {
     358          34 :         m_poOpenFileGDBDS.reset(GDALDataset::Open(osSystemCatalog.c_str(),
     359             :                                                   GDAL_OF_VECTOR, apszDrivers,
     360             :                                                   nullptr, nullptr));
     361             :     }
     362          45 :     if (m_poOpenFileGDBDS != nullptr &&
     363           9 :         m_poOpenFileGDBDS->GetLayer(0) != nullptr)
     364             :     {
     365           9 :         OGRLayer *poCatalogLayer = m_poOpenFileGDBDS->GetLayer(0);
     366             :         const int iNameIndex =
     367           9 :             poCatalogLayer->GetLayerDefn()->GetFieldIndex("Name");
     368           9 :         int i = -1;
     369         106 :         for (auto &poFeat : poCatalogLayer)
     370             :         {
     371          97 :             i++;
     372             :             const std::string osTableName =
     373          97 :                 poFeat->GetFieldAsString(iNameIndex);
     374             : 
     375          97 :             if (osTableName.compare("GDB_Items") == 0)
     376             :             {
     377           9 :                 iGDBItems = i;
     378             :             }
     379             : 
     380             :             // test if layer is already added
     381          97 :             if (GDALDataset::GetLayerByName(osTableName.c_str()))
     382          19 :                 continue;
     383             : 
     384         156 :             const CPLString osLCTableName(CPLString(osTableName).tolower());
     385         156 :             const bool bIsPrivateLayer = osLCTableName.size() >= 4 &&
     386         156 :                                          osLCTableName.substr(0, 4) == "gdb_";
     387          78 :             if (!bIsPrivateLayer)
     388             :             {
     389           6 :                 if (OGRLayer *poLayer =
     390           6 :                         m_poOpenFileGDBDS->GetLayerByName(osTableName.c_str()))
     391             :                 {
     392           5 :                     m_layers.push_back(poLayer);
     393           5 :                     poRootGroup->m_apoLayers.emplace_back(poLayer);
     394             :                 }
     395             :             }
     396             :         }
     397             :     }
     398             : 
     399             :     // Read relationships. Note that we don't use the SDK method for this, as
     400             :     // it's too slow!
     401          36 :     if (iGDBItems >= 0)
     402             :     {
     403             :         const std::string osGDBItems = CPLFormFilenameSafe(
     404           9 :             m_osFSName, CPLSPrintf("a%08x", iGDBItems + 1), "gdbtable");
     405             :         std::unique_ptr<GDALDataset> poGDBItems(GDALDataset::Open(
     406           9 :             osGDBItems.c_str(), GDAL_OF_VECTOR, apszDrivers, nullptr, nullptr));
     407           9 :         if (poGDBItems != nullptr && poGDBItems->GetLayer(0) != nullptr)
     408             :         {
     409           9 :             if (OGRLayer *poItemsLayer = poGDBItems->GetLayer(0))
     410             :             {
     411           9 :                 const int iType = poItemsLayer->FindFieldIndex("Type", true);
     412             :                 const int iDefinition =
     413           9 :                     poItemsLayer->FindFieldIndex("Definition", true);
     414           9 :                 if (iType < 0 || iDefinition < 0)
     415             :                 {
     416           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     417             :                              "Wrong structure for GDB_Items table");
     418           0 :                     return FALSE;
     419             :                 }
     420             : 
     421             :                 // Hunt for relationships in GDB_Items table
     422         270 :                 for (const auto &poFeature : poItemsLayer)
     423             :                 {
     424         522 :                     CPLString osType;
     425         261 :                     const char *pszType = poFeature->GetFieldAsString(iType);
     426         261 :                     if (pszType != nullptr &&
     427         261 :                         EQUAL(pszType, pszRelationshipTypeUUID))
     428             :                     {
     429             :                         // relationship item
     430             :                         auto poRelationship = ParseXMLRelationshipDef(
     431          33 :                             poFeature->GetFieldAsString(iDefinition));
     432          11 :                         if (poRelationship)
     433             :                         {
     434             :                             const std::string relationshipName(
     435          22 :                                 poRelationship->GetName());
     436          11 :                             m_osMapRelationships[relationshipName] =
     437          22 :                                 std::move(poRelationship);
     438             :                         }
     439             :                     }
     440             :                 }
     441             :             }
     442             :         }
     443             :     }
     444             : 
     445          36 :     return true;
     446             : }
     447             : 
     448             : /************************************************************************/
     449             : /*                           TestCapability()                           */
     450             : /************************************************************************/
     451             : 
     452          89 : int FGdbDataSource::TestCapability(const char *pszCap)
     453             : {
     454          89 :     if (EQUAL(pszCap, ODsCMeasuredGeometries))
     455          34 :         return TRUE;
     456          55 :     else if (EQUAL(pszCap, ODsCZGeometries))
     457          34 :         return TRUE;
     458             : 
     459          21 :     return FALSE;
     460             : }
     461             : 
     462             : /************************************************************************/
     463             : /*                              GetLayer()                              */
     464             : /************************************************************************/
     465             : 
     466        4134 : OGRLayer *FGdbDataSource::GetLayer(int iLayer)
     467             : {
     468        4134 :     int count = static_cast<int>(m_layers.size());
     469             : 
     470        4134 :     if (iLayer < 0 || iLayer >= count)
     471           2 :         return nullptr;
     472             :     else
     473        4132 :         return m_layers[iLayer];
     474             : }
     475             : 
     476             : /************************************************************************/
     477             : /*                   OGRFGdbSingleFeatureLayer                          */
     478             : /************************************************************************/
     479             : 
     480             : class OGRFGdbSingleFeatureLayer final : public OGRLayer
     481             : {
     482             :   private:
     483             :     char *pszVal;
     484             :     OGRFeatureDefn *poFeatureDefn;
     485             :     int iNextShapeId;
     486             : 
     487             :   public:
     488             :     OGRFGdbSingleFeatureLayer(const char *pszLayerName, const char *pszVal);
     489             :     virtual ~OGRFGdbSingleFeatureLayer();
     490             : 
     491           0 :     virtual void ResetReading() override
     492             :     {
     493           0 :         iNextShapeId = 0;
     494           0 :     }
     495             : 
     496             :     virtual OGRFeature *GetNextFeature() override;
     497             : 
     498           0 :     virtual OGRFeatureDefn *GetLayerDefn() override
     499             :     {
     500           0 :         return poFeatureDefn;
     501             :     }
     502             : 
     503           0 :     virtual int TestCapability(const char *) override
     504             :     {
     505           0 :         return FALSE;
     506             :     }
     507             : };
     508             : 
     509             : /************************************************************************/
     510             : /*                    OGRFGdbSingleFeatureLayer()                       */
     511             : /************************************************************************/
     512             : 
     513          34 : OGRFGdbSingleFeatureLayer::OGRFGdbSingleFeatureLayer(const char *pszLayerName,
     514          34 :                                                      const char *pszValIn)
     515             : {
     516          34 :     poFeatureDefn = new OGRFeatureDefn(pszLayerName);
     517          34 :     SetDescription(poFeatureDefn->GetName());
     518          34 :     poFeatureDefn->Reference();
     519          34 :     OGRFieldDefn oField("FIELD_1", OFTString);
     520          34 :     poFeatureDefn->AddFieldDefn(&oField);
     521             : 
     522          34 :     iNextShapeId = 0;
     523          34 :     pszVal = pszValIn ? CPLStrdup(pszValIn) : nullptr;
     524          34 : }
     525             : 
     526             : /************************************************************************/
     527             : /*                   ~OGRFGdbSingleFeatureLayer()                       */
     528             : /************************************************************************/
     529             : 
     530          68 : OGRFGdbSingleFeatureLayer::~OGRFGdbSingleFeatureLayer()
     531             : {
     532          34 :     if (poFeatureDefn != nullptr)
     533          34 :         poFeatureDefn->Release();
     534          34 :     CPLFree(pszVal);
     535          68 : }
     536             : 
     537             : /************************************************************************/
     538             : /*                           GetNextFeature()                           */
     539             : /************************************************************************/
     540             : 
     541          51 : OGRFeature *OGRFGdbSingleFeatureLayer::GetNextFeature()
     542             : {
     543          51 :     if (iNextShapeId != 0)
     544          17 :         return nullptr;
     545             : 
     546          34 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     547          34 :     if (pszVal)
     548          34 :         poFeature->SetField(0, pszVal);
     549          34 :     poFeature->SetFID(iNextShapeId++);
     550          34 :     return poFeature;
     551             : }
     552             : 
     553             : /************************************************************************/
     554             : /*                              ExecuteSQL()                            */
     555             : /************************************************************************/
     556             : 
     557         125 : OGRLayer *FGdbDataSource::ExecuteSQL(const char *pszSQLCommand,
     558             :                                      OGRGeometry *poSpatialFilter,
     559             :                                      const char *pszDialect)
     560             : 
     561             : {
     562         125 :     if (m_pGeodatabase == nullptr)
     563           0 :         return nullptr;
     564             : 
     565             :     /* -------------------------------------------------------------------- */
     566             :     /*      Use generic implementation for recognized dialects              */
     567             :     /* -------------------------------------------------------------------- */
     568         125 :     if (IsGenericSQLDialect(pszDialect))
     569           0 :         return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter,
     570           0 :                                        pszDialect);
     571             : 
     572             :     /* -------------------------------------------------------------------- */
     573             :     /*      Special case GetLayerDefinition                                 */
     574             :     /* -------------------------------------------------------------------- */
     575         125 :     if (STARTS_WITH_CI(pszSQLCommand, "GetLayerDefinition "))
     576             :     {
     577          36 :         FGdbLayer *poLayer = (FGdbLayer *)GetLayerByName(
     578          18 :             pszSQLCommand + strlen("GetLayerDefinition "));
     579          18 :         if (poLayer)
     580             :         {
     581          17 :             char *pszVal = nullptr;
     582          17 :             poLayer->GetLayerXML(&pszVal);
     583             :             OGRLayer *poRet =
     584          17 :                 new OGRFGdbSingleFeatureLayer("LayerDefinition", pszVal);
     585          17 :             CPLFree(pszVal);
     586          17 :             return poRet;
     587             :         }
     588             :         else
     589           1 :             return nullptr;
     590             :     }
     591             : 
     592             :     /* -------------------------------------------------------------------- */
     593             :     /*      Special case GetLayerMetadata                                   */
     594             :     /* -------------------------------------------------------------------- */
     595         107 :     if (STARTS_WITH_CI(pszSQLCommand, "GetLayerMetadata "))
     596             :     {
     597          36 :         FGdbLayer *poLayer = (FGdbLayer *)GetLayerByName(
     598          18 :             pszSQLCommand + strlen("GetLayerMetadata "));
     599          18 :         if (poLayer)
     600             :         {
     601          17 :             char *pszVal = nullptr;
     602          17 :             poLayer->GetLayerMetadataXML(&pszVal);
     603             :             OGRLayer *poRet =
     604          17 :                 new OGRFGdbSingleFeatureLayer("LayerMetadata", pszVal);
     605          17 :             CPLFree(pszVal);
     606          17 :             return poRet;
     607             :         }
     608             :         else
     609           1 :             return nullptr;
     610             :     }
     611             : 
     612             :     /* -------------------------------------------------------------------- */
     613             :     /*      Special case REPACK                                             */
     614             :     /* -------------------------------------------------------------------- */
     615          89 :     if (EQUAL(pszSQLCommand, "REPACK"))
     616             :     {
     617           0 :         auto hr = m_pGeodatabase->CompactDatabase();
     618           0 :         if (FAILED(hr))
     619             :         {
     620           0 :             GDBErr(hr, "CompactDatabase failed");
     621           0 :             return new OGRFGdbSingleFeatureLayer("result", "false");
     622             :         }
     623           0 :         return new OGRFGdbSingleFeatureLayer("result", "true");
     624             :     }
     625             : 
     626             :     /* TODO: remove that workaround when the SDK has finally a decent */
     627             :     /* SQL support ! */
     628          89 :     if (STARTS_WITH_CI(pszSQLCommand, "SELECT ") && pszDialect == nullptr)
     629             :     {
     630          85 :         CPLDebug("FGDB", "Support for SELECT is known to be partially "
     631             :                          "non-compliant with FileGDB SDK API v1.2.\n"
     632             :                          "So for now, we use default OGR SQL engine. "
     633             :                          "Explicitly specify -dialect FileGDB\n"
     634             :                          "to use the SQL engine from the FileGDB SDK API");
     635             :         OGRLayer *poLayer =
     636          85 :             GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter, pszDialect);
     637          85 :         if (poLayer)
     638          84 :             m_oSetSelectLayers.insert(poLayer);
     639          85 :         return poLayer;
     640             :     }
     641             : 
     642             :     /* -------------------------------------------------------------------- */
     643             :     /*      Run the SQL                                                     */
     644             :     /* -------------------------------------------------------------------- */
     645           4 :     EnumRows *pEnumRows = new EnumRows;
     646             :     long hr;
     647             :     try
     648             :     {
     649           4 :         hr = m_pGeodatabase->ExecuteSQL(StringToWString(pszSQLCommand), true,
     650             :                                         *pEnumRows);
     651             :     }
     652           0 :     catch (...)
     653             :     {
     654           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     655             :                  "Exception occurred at executing '%s'. Application may "
     656             :                  "become unstable",
     657             :                  pszSQLCommand);
     658           0 :         delete pEnumRows;
     659           0 :         return nullptr;
     660             :     }
     661             : 
     662           4 :     if (FAILED(hr))
     663             :     {
     664           1 :         GDBErr(hr, CPLSPrintf("Failed at executing '%s'", pszSQLCommand));
     665           1 :         delete pEnumRows;
     666           1 :         return nullptr;
     667             :     }
     668             : 
     669           3 :     if (STARTS_WITH_CI(pszSQLCommand, "SELECT "))
     670             :     {
     671           2 :         OGRLayer *poLayer = new FGdbResultLayer(this, pszSQLCommand, pEnumRows);
     672           2 :         m_oSetSelectLayers.insert(poLayer);
     673           2 :         return poLayer;
     674             :     }
     675             :     else
     676             :     {
     677           1 :         delete pEnumRows;
     678           1 :         return nullptr;
     679             :     }
     680             : }
     681             : 
     682             : /************************************************************************/
     683             : /*                           ReleaseResultSet()                         */
     684             : /************************************************************************/
     685             : 
     686         120 : void FGdbDataSource::ReleaseResultSet(OGRLayer *poResultsSet)
     687             : {
     688         120 :     if (poResultsSet)
     689         120 :         m_oSetSelectLayers.erase(poResultsSet);
     690         120 :     delete poResultsSet;
     691         120 : }
     692             : 
     693             : /************************************************************************/
     694             : /*                        GetFieldDomain()                              */
     695             : /************************************************************************/
     696             : 
     697             : const OGRFieldDomain *
     698           3 : FGdbDataSource::GetFieldDomain(const std::string &name) const
     699             : {
     700           3 :     const auto baseRet = GDALDataset::GetFieldDomain(name);
     701           3 :     if (baseRet)
     702           0 :         return baseRet;
     703             : 
     704           6 :     std::string domainDef;
     705             :     const auto hr =
     706           3 :         m_pGeodatabase->GetDomainDefinition(StringToWString(name), domainDef);
     707           3 :     if (FAILED(hr))
     708             :     {
     709             :         // GDBErr(hr, "Failed in GetDomainDefinition()");
     710           1 :         return nullptr;
     711             :     }
     712             : 
     713           4 :     auto poDomain = ParseXMLFieldDomainDef(domainDef);
     714           2 :     if (!poDomain)
     715           0 :         return nullptr;
     716           4 :     const std::string domainName(poDomain->GetName());
     717           2 :     m_oMapFieldDomains[domainName] = std::move(poDomain);
     718           2 :     return GDALDataset::GetFieldDomain(name);
     719             : }
     720             : 
     721             : /************************************************************************/
     722             : /*                        GetFieldDomainNames()                         */
     723             : /************************************************************************/
     724             : 
     725           1 : std::vector<std::string> FGdbDataSource::GetFieldDomainNames(CSLConstList) const
     726             : {
     727           2 :     std::vector<std::wstring> oDomainNamesWList;
     728           1 :     const auto hr = m_pGeodatabase->GetDomains(oDomainNamesWList);
     729           1 :     if (FAILED(hr))
     730             :     {
     731           0 :         GDBErr(hr, "Failed in GetDomains()");
     732           0 :         return std::vector<std::string>();
     733             :     }
     734             : 
     735           2 :     std::vector<std::string> oDomainNamesList;
     736           1 :     oDomainNamesList.reserve(oDomainNamesWList.size());
     737           4 :     for (const auto &osNameW : oDomainNamesWList)
     738             :     {
     739           3 :         oDomainNamesList.emplace_back(WStringToString(osNameW));
     740             :     }
     741           1 :     return oDomainNamesList;
     742             : }
     743             : 
     744             : /************************************************************************/
     745             : /*                        GetRelationshipNames()                        */
     746             : /************************************************************************/
     747             : 
     748             : std::vector<std::string>
     749           3 : FGdbDataSource::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
     750             : 
     751             : {
     752           3 :     std::vector<std::string> oasNames;
     753           3 :     oasNames.reserve(m_osMapRelationships.size());
     754          14 :     for (auto it = m_osMapRelationships.begin();
     755          25 :          it != m_osMapRelationships.end(); ++it)
     756             :     {
     757          11 :         oasNames.emplace_back(it->first);
     758             :     }
     759           3 :     return oasNames;
     760             : }
     761             : 
     762             : /************************************************************************/
     763             : /*                        GetRelationship()                             */
     764             : /************************************************************************/
     765             : 
     766             : const GDALRelationship *
     767           8 : FGdbDataSource::GetRelationship(const std::string &name) const
     768             : 
     769             : {
     770           8 :     auto it = m_osMapRelationships.find(name);
     771           8 :     if (it == m_osMapRelationships.end())
     772           1 :         return nullptr;
     773             : 
     774           7 :     return it->second.get();
     775             : }

Generated by: LCOV version 1.14