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
|