LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogr_miattrind.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 218 283 77.0 %
Date: 2025-01-18 12:42:00 Functions: 21 26 80.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements interface to MapInfo .ID files used as attribute
       5             :  *           indexes.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2003, Frank Warmerdam
      10             :  * Copyright (c) 2008-2010, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "ogr_attrind.h"
      16             : 
      17             : #ifdef HAVE_MITAB
      18             : 
      19             : #include "mitab/mitab_priv.h"
      20             : #include "cpl_minixml.h"
      21             : 
      22             : /************************************************************************/
      23             : /*                            OGRMIAttrIndex                            */
      24             : /*                                                                      */
      25             : /*      MapInfo .ID implementation of access to one fields              */
      26             : /*      indexing.                                                       */
      27             : /************************************************************************/
      28             : 
      29             : class OGRMILayerAttrIndex;
      30             : 
      31             : class OGRMIAttrIndex : public OGRAttrIndex
      32             : {
      33             :     CPL_DISALLOW_COPY_ASSIGN(OGRMIAttrIndex)
      34             : 
      35             :   public:
      36             :     int iIndex;
      37             :     TABINDFile *poINDFile;
      38             :     OGRMILayerAttrIndex *poLIndex;
      39             :     OGRFieldDefn *poFldDefn;
      40             : 
      41             :     int iField;
      42             : 
      43             :     OGRMIAttrIndex(OGRMILayerAttrIndex *, int iIndex, int iField);
      44             :     ~OGRMIAttrIndex();
      45             : 
      46             :     GByte *BuildKey(OGRField *psKey);
      47             :     GIntBig GetFirstMatch(OGRField *psKey) override;
      48             :     GIntBig *GetAllMatches(OGRField *psKey) override;
      49             :     GIntBig *GetAllMatches(OGRField *psKey, GIntBig *panFIDList, int *nFIDCount,
      50             :                            int *nLength) override;
      51             : 
      52             :     OGRErr AddEntry(OGRField *psKey, GIntBig nFID) override;
      53             :     OGRErr RemoveEntry(OGRField *psKey, GIntBig nFID) override;
      54             : 
      55             :     OGRErr Clear() override;
      56             : };
      57             : 
      58             : /************************************************************************/
      59             : /* ==================================================================== */
      60             : /*                         OGRMILayerAttrIndex                          */
      61             : /*                                                                      */
      62             : /*      MapInfo .ID specific implementation of a layer attribute        */
      63             : /*      index.                                                          */
      64             : /* ==================================================================== */
      65             : /************************************************************************/
      66             : 
      67             : class OGRMILayerAttrIndex final : public OGRLayerAttrIndex
      68             : {
      69             :     CPL_DISALLOW_COPY_ASSIGN(OGRMILayerAttrIndex)
      70             : 
      71             :   public:
      72             :     TABINDFile *poINDFile;
      73             : 
      74             :     int nIndexCount;
      75             :     OGRMIAttrIndex **papoIndexList;
      76             : 
      77             :     char *pszMetadataFilename;
      78             :     char *pszMIINDFilename;
      79             : 
      80             :     int bINDAsReadOnly;
      81             :     int bUnlinkINDFile;
      82             : 
      83             :     OGRMILayerAttrIndex();
      84             :     virtual ~OGRMILayerAttrIndex();
      85             : 
      86             :     /* base class virtual methods */
      87             :     OGRErr Initialize(const char *pszIndexPath, OGRLayer *) override;
      88             :     OGRErr CreateIndex(int iField) override;
      89             :     OGRErr DropIndex(int iField) override;
      90             :     OGRErr IndexAllFeatures(int iField = -1) override;
      91             : 
      92             :     OGRErr AddToIndex(OGRFeature *poFeature, int iField = -1) override;
      93             :     OGRErr RemoveFromIndex(OGRFeature *poFeature) override;
      94             : 
      95             :     OGRAttrIndex *GetFieldIndex(int iField) override;
      96             : 
      97             :     /* custom to OGRMILayerAttrIndex */
      98             :     OGRErr SaveConfigToXML();
      99             :     OGRErr LoadConfigFromXML();
     100             :     OGRErr LoadConfigFromXML(const char *pszRawXML);
     101             :     void AddAttrInd(int iField, int iINDIndex);
     102             : 
     103          55 :     OGRLayer *GetLayer()
     104             :     {
     105          55 :         return poLayer;
     106             :     }
     107             : };
     108             : 
     109             : /************************************************************************/
     110             : /*                        OGRMILayerAttrIndex()                         */
     111             : /************************************************************************/
     112             : 
     113         164 : OGRMILayerAttrIndex::OGRMILayerAttrIndex()
     114             :     : poINDFile(nullptr), nIndexCount(0), papoIndexList(nullptr),
     115             :       pszMetadataFilename(nullptr), pszMIINDFilename(nullptr),
     116         164 :       bINDAsReadOnly(TRUE), bUnlinkINDFile(FALSE)
     117             : {
     118         164 : }
     119             : 
     120             : /************************************************************************/
     121             : /*                        ~OGRMILayerAttrIndex()                        */
     122             : /************************************************************************/
     123             : 
     124         328 : OGRMILayerAttrIndex::~OGRMILayerAttrIndex()
     125             : 
     126             : {
     127         164 :     if (poINDFile != nullptr)
     128             :     {
     129          32 :         poINDFile->Close();
     130          32 :         delete poINDFile;
     131          32 :         poINDFile = nullptr;
     132             :     }
     133             : 
     134         164 :     if (bUnlinkINDFile)
     135           5 :         VSIUnlink(pszMIINDFilename);
     136             : 
     137         209 :     for (int i = 0; i < nIndexCount; i++)
     138          45 :         delete papoIndexList[i];
     139         164 :     CPLFree(papoIndexList);
     140             : 
     141         164 :     CPLFree(pszMIINDFilename);
     142         164 :     CPLFree(pszMetadataFilename);
     143         328 : }
     144             : 
     145             : /************************************************************************/
     146             : /*                             Initialize()                             */
     147             : /************************************************************************/
     148             : 
     149         164 : OGRErr OGRMILayerAttrIndex::Initialize(const char *pszIndexPathIn,
     150             :                                        OGRLayer *poLayerIn)
     151             : 
     152             : {
     153         164 :     if (poLayerIn == poLayer)
     154           0 :         return OGRERR_NONE;
     155             : 
     156             :     /* -------------------------------------------------------------------- */
     157             :     /*      Capture input information and form static pathnames.            */
     158             :     /* -------------------------------------------------------------------- */
     159         164 :     poLayer = poLayerIn;
     160             : 
     161         164 :     pszIndexPath = CPLStrdup(pszIndexPathIn);
     162             : 
     163             :     /* try to process the XML string directly */
     164         164 :     if (STARTS_WITH_CI(pszIndexPathIn, "<OGRMILayerAttrIndex>"))
     165           6 :         return LoadConfigFromXML(pszIndexPathIn);
     166             : 
     167         158 :     pszMetadataFilename =
     168         158 :         CPLStrdup(CPLResetExtensionSafe(pszIndexPathIn, "idm").c_str());
     169             : 
     170         158 :     pszMIINDFilename =
     171         158 :         CPLStrdup(CPLResetExtensionSafe(pszIndexPathIn, "ind").c_str());
     172             : 
     173             :     /* -------------------------------------------------------------------- */
     174             :     /*      If a metadata file already exists, load it.                     */
     175             :     /* -------------------------------------------------------------------- */
     176             :     OGRErr eErr;
     177             :     VSIStatBuf sStat;
     178             : 
     179         158 :     if (VSIStat(pszMetadataFilename, &sStat) == 0)
     180             :     {
     181          11 :         eErr = LoadConfigFromXML();
     182          11 :         if (eErr != OGRERR_NONE)
     183           0 :             return eErr;
     184             :     }
     185             : 
     186         158 :     return OGRERR_NONE;
     187             : }
     188             : 
     189             : /************************************************************************/
     190             : /*                         LoadConfigFromXML()                          */
     191             : /************************************************************************/
     192             : 
     193          17 : OGRErr OGRMILayerAttrIndex::LoadConfigFromXML(const char *pszRawXML)
     194             : 
     195             : {
     196             :     /* -------------------------------------------------------------------- */
     197             :     /*      Parse the XML.                                                  */
     198             :     /* -------------------------------------------------------------------- */
     199          17 :     CPLXMLNode *psRoot = CPLParseXMLString(pszRawXML);
     200             : 
     201          17 :     if (psRoot == nullptr)
     202           0 :         return OGRERR_FAILURE;
     203             : 
     204             :     /* -------------------------------------------------------------------- */
     205             :     /*      Open the index file.                                            */
     206             :     /* -------------------------------------------------------------------- */
     207          17 :     poINDFile = new TABINDFile();
     208             : 
     209          17 :     if (pszMIINDFilename == nullptr)
     210           6 :         pszMIINDFilename =
     211           6 :             CPLStrdup(CPLGetXMLValue(psRoot, "MIIDFilename", ""));
     212             : 
     213          17 :     if (pszMIINDFilename == nullptr)
     214           0 :         return OGRERR_FAILURE;
     215             : 
     216             :     /* NOTE: Replaced r+ with r according to explanation in Ticket #1620.
     217             :      * This change has to be observed if it doesn't cause any
     218             :      * problems in future. (mloskot)
     219             :      */
     220          17 :     if (poINDFile->Open(pszMIINDFilename, "r") != 0)
     221             :     {
     222           0 :         CPLDestroyXMLNode(psRoot);
     223           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open index file %s.",
     224             :                  pszMIINDFilename);
     225           0 :         return OGRERR_FAILURE;
     226             :     }
     227             :     /* -------------------------------------------------------------------- */
     228             :     /*      Process each attrindex.                                         */
     229             :     /* -------------------------------------------------------------------- */
     230          61 :     for (CPLXMLNode *psAttrIndex = psRoot->psChild; psAttrIndex != nullptr;
     231          44 :          psAttrIndex = psAttrIndex->psNext)
     232             :     {
     233          44 :         if (psAttrIndex->eType != CXT_Element ||
     234          44 :             !EQUAL(psAttrIndex->pszValue, "OGRMIAttrIndex"))
     235          17 :             continue;
     236             : 
     237          27 :         int iField = atoi(CPLGetXMLValue(psAttrIndex, "FieldIndex", "-1"));
     238          27 :         int iIndexIndex = atoi(CPLGetXMLValue(psAttrIndex, "IndexIndex", "-1"));
     239             : 
     240          27 :         if (iField == -1 || iIndexIndex == -1)
     241             :         {
     242           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     243             :                      "Skipping corrupt OGRMIAttrIndex entry.");
     244           0 :             continue;
     245             :         }
     246             : 
     247          27 :         AddAttrInd(iField, iIndexIndex);
     248             :     }
     249             : 
     250          17 :     CPLDestroyXMLNode(psRoot);
     251             : 
     252          34 :     CPLDebug("OGR", "Restored %d field indexes for layer %s from %s on %s.",
     253          17 :              nIndexCount, poLayer->GetLayerDefn()->GetName(),
     254          17 :              pszMetadataFilename ? pszMetadataFilename : "--unknown--",
     255             :              pszMIINDFilename);
     256             : 
     257          17 :     return OGRERR_NONE;
     258             : }
     259             : 
     260          11 : OGRErr OGRMILayerAttrIndex::LoadConfigFromXML()
     261             : {
     262          11 :     CPLAssert(poINDFile == nullptr);
     263             : 
     264             :     /* -------------------------------------------------------------------- */
     265             :     /*      Read the XML file.                                              */
     266             :     /* -------------------------------------------------------------------- */
     267          11 :     VSILFILE *fp = VSIFOpenL(pszMetadataFilename, "rb");
     268          11 :     if (fp == nullptr)
     269           0 :         return OGRERR_FAILURE;
     270             : 
     271          11 :     if (VSIFSeekL(fp, 0, SEEK_END) != 0)
     272             :     {
     273           0 :         VSIFCloseL(fp);
     274           0 :         return OGRERR_FAILURE;
     275             :     }
     276          11 :     const vsi_l_offset nXMLSize = VSIFTellL(fp);
     277          11 :     if (nXMLSize > 10 * 1024 * 1024 || VSIFSeekL(fp, 0, SEEK_SET) != 0)
     278             :     {
     279           0 :         VSIFCloseL(fp);
     280           0 :         return OGRERR_FAILURE;
     281             :     }
     282             : 
     283             :     char *pszRawXML =
     284          11 :         static_cast<char *>(CPLMalloc(static_cast<size_t>(nXMLSize) + 1));
     285          11 :     pszRawXML[nXMLSize] = '\0';
     286          11 :     if (VSIFReadL(pszRawXML, static_cast<size_t>(nXMLSize), 1, fp) != 1)
     287             :     {
     288           0 :         VSIFCloseL(fp);
     289           0 :         return OGRERR_FAILURE;
     290             :     }
     291             : 
     292          11 :     VSIFCloseL(fp);
     293             : 
     294          11 :     OGRErr eErr = LoadConfigFromXML(pszRawXML);
     295          11 :     CPLFree(pszRawXML);
     296             : 
     297          11 :     return eErr;
     298             : }
     299             : 
     300             : /************************************************************************/
     301             : /*                          SaveConfigToXML()                           */
     302             : /************************************************************************/
     303             : 
     304          33 : OGRErr OGRMILayerAttrIndex::SaveConfigToXML()
     305             : 
     306             : {
     307          33 :     if (nIndexCount == 0)
     308           0 :         return OGRERR_NONE;
     309             : 
     310             :     /* -------------------------------------------------------------------- */
     311             :     /*      Create the XML tree corresponding to this layer.                */
     312             :     /* -------------------------------------------------------------------- */
     313             :     CPLXMLNode *psRoot =
     314          33 :         CPLCreateXMLNode(nullptr, CXT_Element, "OGRMILayerAttrIndex");
     315             : 
     316          33 :     CPLCreateXMLElementAndValue(psRoot, "MIIDFilename",
     317          33 :                                 CPLGetFilename(pszMIINDFilename));
     318             : 
     319          79 :     for (int i = 0; i < nIndexCount; i++)
     320             :     {
     321          46 :         OGRMIAttrIndex *poAI = papoIndexList[i];
     322             :         CPLXMLNode *psIndex =
     323          46 :             CPLCreateXMLNode(psRoot, CXT_Element, "OGRMIAttrIndex");
     324             : 
     325          46 :         CPLCreateXMLElementAndValue(psIndex, "FieldIndex",
     326             :                                     CPLSPrintf("%d", poAI->iField));
     327             : 
     328          46 :         CPLCreateXMLElementAndValue(
     329             :             psIndex, "FieldName",
     330          46 :             poLayer->GetLayerDefn()->GetFieldDefn(poAI->iField)->GetNameRef());
     331             : 
     332          46 :         CPLCreateXMLElementAndValue(psIndex, "IndexIndex",
     333             :                                     CPLSPrintf("%d", poAI->iIndex));
     334             :     }
     335             : 
     336             :     /* -------------------------------------------------------------------- */
     337             :     /*      Save it.                                                        */
     338             :     /* -------------------------------------------------------------------- */
     339          33 :     char *pszRawXML = CPLSerializeXMLTree(psRoot);
     340             : 
     341          33 :     CPLDestroyXMLNode(psRoot);
     342             : 
     343          33 :     FILE *fp = VSIFOpen(pszMetadataFilename, "wb");
     344          33 :     if (fp == nullptr)
     345             :     {
     346           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to pen `%s' for write.",
     347             :                  pszMetadataFilename);
     348           0 :         CPLFree(pszRawXML);
     349           0 :         return OGRERR_FAILURE;
     350             :     }
     351             : 
     352          33 :     OGRErr eErr = (VSIFWrite(pszRawXML, strlen(pszRawXML), 1, fp) == 1)
     353          33 :                       ? OGRERR_NONE
     354          33 :                       : OGRERR_FAILURE;
     355          33 :     VSIFClose(fp);
     356             : 
     357          33 :     CPLFree(pszRawXML);
     358             : 
     359          33 :     return eErr;
     360             : }
     361             : 
     362             : /************************************************************************/
     363             : /*                          IndexAllFeatures()                          */
     364             : /************************************************************************/
     365             : 
     366          28 : OGRErr OGRMILayerAttrIndex::IndexAllFeatures(int iField)
     367             : 
     368             : {
     369          28 :     poLayer->ResetReading();
     370             : 
     371          28 :     OGRFeature *poFeature = nullptr;
     372         520 :     while ((poFeature = poLayer->GetNextFeature()) != nullptr)
     373             :     {
     374         492 :         const OGRErr eErr = AddToIndex(poFeature, iField);
     375             : 
     376         492 :         delete poFeature;
     377             : 
     378         492 :         if (eErr != OGRERR_NONE)
     379           0 :             return eErr;
     380             :     }
     381             : 
     382          28 :     poLayer->ResetReading();
     383             : 
     384          28 :     return OGRERR_NONE;
     385             : }
     386             : 
     387             : /************************************************************************/
     388             : /*                            CreateIndex()                             */
     389             : /*                                                                      */
     390             : /*      Create an index corresponding to the indicated field, but do    */
     391             : /*      not populate it.  Use IndexAllFeatures() for that.              */
     392             : /************************************************************************/
     393             : 
     394          28 : OGRErr OGRMILayerAttrIndex::CreateIndex(int iField)
     395             : 
     396             : {
     397             :     /* -------------------------------------------------------------------- */
     398             :     /*      Do we have an open .ID file yet?  If not, create it now.        */
     399             :     /* -------------------------------------------------------------------- */
     400          28 :     if (poINDFile == nullptr)
     401             :     {
     402          15 :         poINDFile = new TABINDFile();
     403          15 :         if (poINDFile->Open(pszMIINDFilename, "w+") != 0)
     404             :         {
     405           0 :             delete poINDFile;
     406           0 :             poINDFile = nullptr;
     407             : 
     408           0 :             CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s.",
     409             :                      pszMIINDFilename);
     410           0 :             return OGRERR_FAILURE;
     411             :         }
     412             :     }
     413          13 :     else if (bINDAsReadOnly)
     414             :     {
     415          13 :         poINDFile->Close();
     416          13 :         if (poINDFile->Open(pszMIINDFilename, "r+") != 0)
     417             :         {
     418           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     419             :                      "Failed to open %s as write-only.", pszMIINDFilename);
     420             : 
     421           0 :             if (poINDFile->Open(pszMIINDFilename, "r") != 0)
     422             :             {
     423           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     424             :                          "Cannot re-open %s as read-only.", pszMIINDFilename);
     425           0 :                 delete poINDFile;
     426           0 :                 poINDFile = nullptr;
     427             :             }
     428             : 
     429           0 :             return OGRERR_FAILURE;
     430             :         }
     431             :         else
     432             :         {
     433          13 :             bINDAsReadOnly = FALSE;
     434             :         }
     435             :     }
     436             : 
     437             :     /* -------------------------------------------------------------------- */
     438             :     /*      Do we have this field indexed already?                          */
     439             :     /* -------------------------------------------------------------------- */
     440          28 :     OGRFieldDefn *poFldDefn = poLayer->GetLayerDefn()->GetFieldDefn(iField);
     441             : 
     442          41 :     for (int i = 0; i < nIndexCount; i++)
     443             :     {
     444          13 :         if (papoIndexList[i]->iField == iField)
     445             :         {
     446           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     447             :                      "It seems we already have an index for field %d/%s\n"
     448             :                      "of layer %s.",
     449             :                      iField, poFldDefn->GetNameRef(),
     450           0 :                      poLayer->GetLayerDefn()->GetName());
     451           0 :             return OGRERR_FAILURE;
     452             :         }
     453             :     }
     454             : 
     455             :     /* -------------------------------------------------------------------- */
     456             :     /*      What is the corresponding field type in TAB?  Note that we      */
     457             :     /*      don't allow indexing of any of the list types.                  */
     458             :     /* -------------------------------------------------------------------- */
     459             :     TABFieldType eTABFT;
     460          28 :     int nFieldWidth = 0;
     461             : 
     462          28 :     switch (poFldDefn->GetType())
     463             :     {
     464          13 :         case OFTInteger:
     465          13 :             eTABFT = TABFInteger;
     466          13 :             break;
     467             : 
     468           1 :         case OFTReal:
     469           1 :             eTABFT = TABFFloat;
     470           1 :             break;
     471             : 
     472          14 :         case OFTString:
     473          14 :             eTABFT = TABFChar;
     474          14 :             if (poFldDefn->GetWidth() > 0)
     475          14 :                 nFieldWidth = poFldDefn->GetWidth();
     476             :             else
     477           0 :                 nFieldWidth = 64;
     478          14 :             break;
     479             : 
     480           0 :         default:
     481           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     482             :                      "Indexing not support for the field type of field %s.",
     483             :                      poFldDefn->GetNameRef());
     484           0 :             return OGRERR_FAILURE;
     485             :     }
     486             : 
     487             :     /* -------------------------------------------------------------------- */
     488             :     /*      Create the index.                                               */
     489             :     /* -------------------------------------------------------------------- */
     490          28 :     const int iINDIndex = poINDFile->CreateIndex(eTABFT, nFieldWidth);
     491             : 
     492             :     // CreateIndex() reports its own errors.
     493          28 :     if (iINDIndex < 0)
     494           0 :         return OGRERR_FAILURE;
     495             : 
     496          28 :     AddAttrInd(iField, iINDIndex);
     497             : 
     498          28 :     bUnlinkINDFile = FALSE;
     499             : 
     500             :     /* -------------------------------------------------------------------- */
     501             :     /*      Save the new configuration.                                     */
     502             :     /* -------------------------------------------------------------------- */
     503          28 :     return SaveConfigToXML();
     504             : }
     505             : 
     506             : /************************************************************************/
     507             : /*                             DropIndex()                              */
     508             : /*                                                                      */
     509             : /*      For now we don't have any capability to remove index data       */
     510             : /*      from the MapInfo index file, so we just limit ourselves to      */
     511             : /*      ignoring it from now on.                                        */
     512             : /************************************************************************/
     513             : 
     514          10 : OGRErr OGRMILayerAttrIndex::DropIndex(int iField)
     515             : 
     516             : {
     517             :     /* -------------------------------------------------------------------- */
     518             :     /*      Do we have this field indexed already?                          */
     519             :     /* -------------------------------------------------------------------- */
     520          10 :     OGRFieldDefn *poFldDefn = poLayer->GetLayerDefn()->GetFieldDefn(iField);
     521             : 
     522          10 :     int i = 0;
     523          10 :     for (; i < nIndexCount; i++)
     524             :     {
     525          10 :         if (papoIndexList[i]->iField == iField)
     526          10 :             break;
     527             :     }
     528             : 
     529          10 :     if (i == nIndexCount)
     530             :     {
     531           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     532             :                  "DROP INDEX on field (%s) that doesn't have an index.",
     533             :                  poFldDefn->GetNameRef());
     534           0 :         return OGRERR_FAILURE;
     535             :     }
     536             : 
     537             :     /* -------------------------------------------------------------------- */
     538             :     /*      Remove from the list.                                           */
     539             :     /* -------------------------------------------------------------------- */
     540          10 :     OGRMIAttrIndex *poAI = papoIndexList[i];
     541             : 
     542          10 :     memmove(papoIndexList + i, papoIndexList + i + 1,
     543          10 :             sizeof(void *) * (nIndexCount - i - 1));
     544             : 
     545          10 :     delete poAI;
     546             : 
     547          10 :     nIndexCount--;
     548             : 
     549             :     /* -------------------------------------------------------------------- */
     550             :     /*      Save the new configuration, or if there is nothing left try     */
     551             :     /*      to clean up the index files.                                    */
     552             :     /* -------------------------------------------------------------------- */
     553             : 
     554          10 :     if (nIndexCount > 0)
     555           5 :         return SaveConfigToXML();
     556             :     else
     557             :     {
     558           5 :         bUnlinkINDFile = TRUE;
     559           5 :         VSIUnlink(pszMetadataFilename);
     560             : 
     561           5 :         return OGRERR_NONE;
     562             :     }
     563             : }
     564             : 
     565             : /************************************************************************/
     566             : /*                             AddAttrInd()                             */
     567             : /************************************************************************/
     568             : 
     569          55 : void OGRMILayerAttrIndex::AddAttrInd(int iField, int iINDIndex)
     570             : 
     571             : {
     572          55 :     OGRMIAttrIndex *poAttrInd = new OGRMIAttrIndex(this, iINDIndex, iField);
     573             : 
     574          55 :     nIndexCount++;
     575          55 :     papoIndexList = static_cast<OGRMIAttrIndex **>(
     576          55 :         CPLRealloc(papoIndexList, sizeof(void *) * nIndexCount));
     577             : 
     578          55 :     papoIndexList[nIndexCount - 1] = poAttrInd;
     579          55 : }
     580             : 
     581             : /************************************************************************/
     582             : /*                         GetFieldAttrIndex()                          */
     583             : /************************************************************************/
     584             : 
     585         389 : OGRAttrIndex *OGRMILayerAttrIndex::GetFieldIndex(int iField)
     586             : 
     587             : {
     588         407 :     for (int i = 0; i < nIndexCount; i++)
     589             :     {
     590          45 :         if (papoIndexList[i]->iField == iField)
     591          27 :             return papoIndexList[i];
     592             :     }
     593             : 
     594         362 :     return nullptr;
     595             : }
     596             : 
     597             : /************************************************************************/
     598             : /*                             AddToIndex()                             */
     599             : /************************************************************************/
     600             : 
     601         492 : OGRErr OGRMILayerAttrIndex::AddToIndex(OGRFeature *poFeature, int iTargetField)
     602             : 
     603             : {
     604         492 :     OGRErr eErr = OGRERR_NONE;
     605             : 
     606         492 :     if (poFeature->GetFID() == OGRNullFID)
     607             :     {
     608           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     609             :                  "Attempt to index feature with no FID.");
     610           0 :         return OGRERR_FAILURE;
     611             :     }
     612             : 
     613        1210 :     for (int i = 0; i < nIndexCount && eErr == OGRERR_NONE; i++)
     614             :     {
     615         718 :         int iField = papoIndexList[i]->iField;
     616             : 
     617         718 :         if (iTargetField != -1 && iTargetField != iField)
     618         226 :             continue;
     619             : 
     620         492 :         if (!poFeature->IsFieldSetAndNotNull(iField))
     621           0 :             continue;
     622             : 
     623         492 :         eErr = papoIndexList[i]->AddEntry(poFeature->GetRawFieldRef(iField),
     624         492 :                                           poFeature->GetFID());
     625             :     }
     626             : 
     627         492 :     return eErr;
     628             : }
     629             : 
     630             : /************************************************************************/
     631             : /*                          RemoveFromIndex()                           */
     632             : /************************************************************************/
     633             : 
     634           0 : OGRErr OGRMILayerAttrIndex::RemoveFromIndex(OGRFeature * /*poFeature*/)
     635             : 
     636             : {
     637           0 :     return OGRERR_UNSUPPORTED_OPERATION;
     638             : }
     639             : 
     640             : /************************************************************************/
     641             : /*                     OGRCreateDefaultLayerIndex()                     */
     642             : /************************************************************************/
     643             : 
     644         164 : OGRLayerAttrIndex *OGRCreateDefaultLayerIndex()
     645             : 
     646             : {
     647         164 :     return new OGRMILayerAttrIndex();
     648             : }
     649             : 
     650             : /************************************************************************/
     651             : /* ==================================================================== */
     652             : /*                            OGRMIAttrIndex                            */
     653             : /* ==================================================================== */
     654             : /************************************************************************/
     655             : 
     656             : /* class declared at top of file */
     657             : 
     658             : /************************************************************************/
     659             : /*                           OGRMIAttrIndex()                           */
     660             : /************************************************************************/
     661             : 
     662          55 : OGRMIAttrIndex::OGRMIAttrIndex(OGRMILayerAttrIndex *poLayerIndex, int iIndexIn,
     663          55 :                                int iFieldIn)
     664          55 :     : iIndex(iIndexIn), poINDFile(poLayerIndex->poINDFile),
     665             :       poLIndex(poLayerIndex),
     666             :       poFldDefn(
     667          55 :           poLayerIndex->GetLayer()->GetLayerDefn()->GetFieldDefn(iFieldIn)),
     668          55 :       iField(iFieldIn)
     669             : {
     670          55 : }
     671             : 
     672             : /************************************************************************/
     673             : /*                          ~OGRMIAttrIndex()                           */
     674             : /************************************************************************/
     675             : 
     676         110 : OGRMIAttrIndex::~OGRMIAttrIndex()
     677             : {
     678         110 : }
     679             : 
     680             : /************************************************************************/
     681             : /*                              AddEntry()                              */
     682             : /************************************************************************/
     683             : 
     684         492 : OGRErr OGRMIAttrIndex::AddEntry(OGRField *psKey, GIntBig nFID)
     685             : 
     686             : {
     687         492 :     if (psKey == nullptr)
     688           0 :         return OGRERR_FAILURE;
     689             : 
     690         492 :     if (nFID >= INT_MAX)
     691           0 :         return OGRERR_FAILURE;
     692             : 
     693         492 :     GByte *pabyKey = BuildKey(psKey);
     694             : 
     695         492 :     if (pabyKey == nullptr)
     696           0 :         return OGRERR_FAILURE;
     697             : 
     698         492 :     if (poINDFile->AddEntry(iIndex, pabyKey, static_cast<int>(nFID) + 1) != 0)
     699           0 :         return OGRERR_FAILURE;
     700             :     else
     701         492 :         return OGRERR_NONE;
     702             : }
     703             : 
     704             : /************************************************************************/
     705             : /*                            RemoveEntry()                             */
     706             : /************************************************************************/
     707             : 
     708           0 : OGRErr OGRMIAttrIndex::RemoveEntry(OGRField * /*psKey*/, GIntBig /*nFID*/)
     709             : 
     710             : {
     711           0 :     return OGRERR_UNSUPPORTED_OPERATION;
     712             : }
     713             : 
     714             : /************************************************************************/
     715             : /*                              BuildKey()                              */
     716             : /************************************************************************/
     717             : 
     718         521 : GByte *OGRMIAttrIndex::BuildKey(OGRField *psKey)
     719             : 
     720             : {
     721         521 :     GByte *ret = nullptr;
     722         521 :     switch (poFldDefn->GetType())
     723             :     {
     724         241 :         case OFTInteger:
     725         241 :             ret = poINDFile->BuildKey(iIndex, psKey->Integer);
     726         241 :             break;
     727             : 
     728           2 :         case OFTInteger64:
     729             :         {
     730           2 :             if (!CPL_INT64_FITS_ON_INT32(psKey->Integer64))
     731             :             {
     732           0 :                 CPLError(
     733             :                     CE_Warning, CPLE_NotSupported,
     734             :                     "64bit integer value passed to OGRMIAttrIndex::BuildKey()");
     735             :             }
     736             :             ret =
     737           2 :                 poINDFile->BuildKey(iIndex, static_cast<int>(psKey->Integer64));
     738           2 :             break;
     739             :         }
     740             : 
     741           8 :         case OFTReal:
     742           8 :             ret = poINDFile->BuildKey(iIndex, psKey->Real);
     743           8 :             break;
     744             : 
     745         270 :         case OFTString:
     746         270 :             ret = poINDFile->BuildKey(iIndex, psKey->String);
     747         270 :             break;
     748             : 
     749           0 :         default:
     750           0 :             CPLAssert(false);
     751             :             break;
     752             :     }
     753         521 :     return ret;
     754             : }
     755             : 
     756             : /************************************************************************/
     757             : /*                           GetFirstMatch()                            */
     758             : /************************************************************************/
     759             : 
     760           0 : GIntBig OGRMIAttrIndex::GetFirstMatch(OGRField *psKey)
     761             : 
     762             : {
     763           0 :     GByte *pabyKey = BuildKey(psKey);
     764           0 :     const GIntBig nFID = poINDFile->FindFirst(iIndex, pabyKey);
     765           0 :     if (nFID < 1)
     766           0 :         return OGRNullFID;
     767             :     else
     768           0 :         return nFID - 1;
     769             : }
     770             : 
     771             : /************************************************************************/
     772             : /*                           GetAllMatches()                            */
     773             : /************************************************************************/
     774             : 
     775          29 : GIntBig *OGRMIAttrIndex::GetAllMatches(OGRField *psKey, GIntBig *panFIDList,
     776             :                                        int *nFIDCount, int *nLength)
     777             : {
     778          29 :     GByte *pabyKey = BuildKey(psKey);
     779             : 
     780          29 :     if (panFIDList == nullptr)
     781             :     {
     782          27 :         panFIDList = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig) * 2));
     783          27 :         *nFIDCount = 0;
     784          27 :         *nLength = 2;
     785             :     }
     786             : 
     787          29 :     GIntBig nFID = poINDFile->FindFirst(iIndex, pabyKey);
     788          65 :     while (nFID > 0)
     789             :     {
     790          36 :         if (*nFIDCount >= *nLength - 1)
     791             :         {
     792           7 :             *nLength = (*nLength) * 2 + 10;
     793             :             panFIDList = static_cast<GIntBig *>(
     794           7 :                 CPLRealloc(panFIDList, sizeof(GIntBig) * (*nLength)));
     795             :         }
     796          36 :         panFIDList[(*nFIDCount)++] = nFID - 1;
     797             : 
     798          36 :         nFID = poINDFile->FindNext(iIndex, pabyKey);
     799             :     }
     800             : 
     801          29 :     panFIDList[*nFIDCount] = OGRNullFID;
     802             : 
     803          29 :     return panFIDList;
     804             : }
     805             : 
     806           0 : GIntBig *OGRMIAttrIndex::GetAllMatches(OGRField *psKey)
     807             : {
     808             :     int nFIDCount, nLength;
     809           0 :     return GetAllMatches(psKey, nullptr, &nFIDCount, &nLength);
     810             : }
     811             : 
     812             : /************************************************************************/
     813             : /*                               Clear()                                */
     814             : /************************************************************************/
     815             : 
     816           0 : OGRErr OGRMIAttrIndex::Clear()
     817             : 
     818             : {
     819           0 :     return OGRERR_UNSUPPORTED_OPERATION;
     820             : }
     821             : 
     822             : #else
     823             : 
     824             : /************************************************************************/
     825             : /*                     OGRCreateDefaultLayerIndex()                     */
     826             : /************************************************************************/
     827             : 
     828             : OGRLayerAttrIndex *OGRCreateDefaultLayerIndex()
     829             : 
     830             : {
     831             :     return nullptr;
     832             : }
     833             : 
     834             : #endif

Generated by: LCOV version 1.14