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