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
|