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

Generated by: LCOV version 1.14